五、读例程
将一些特定的模块调试好,就是那些使用别的软件(如汉字取模)或者硬件(USB转TTL)的,就打开资料包里面的例程读一读
像我们这种标准库开发是很有必要将代码读一读的,我们要懂得深层的道理,可能刚开始会有点生涩,但在打好C语言基础的情况下读这些代码虽然也不是很容易但是随着阅读代码量的增多以及遇到不会的知识在网络查找的增多,我们的知识涉及到的底层会越来越深
1、初始化函数
各个模块的初始化函数一般都是对GPIO进行初始化,设置GPIO的各种属性,比如下面这个OLED例程的OLED_Init函数
代码语言:javascript复制void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//使能A端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA0,1
GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA2
GPIO_SetBits(GPIOA,GPIO_Pin_2);
OLED_RES_Clr();
delay_ms(200);
OLED_RES_Set();
OLED_WR_Byte(0xAE,OLED_CMD);
//--turn off oled panel
OLED_WR_Byte(0x00,OLED_CMD);
//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);
//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);
//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WR_Byte(0x81,OLED_CMD);
//--set contrast control register
OLED_WR_Byte(0xCF,OLED_CMD);
// Set SEG Output Current Brightness
OLED_WR_Byte(0xA1,OLED_CMD);
//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WR_Byte(0xC8,OLED_CMD);
//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xA6,OLED_CMD);
//--set normal display
OLED_WR_Byte(0xA8,OLED_CMD);
//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD);
//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);
//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);
//-not offset
OLED_WR_Byte(0xd5,OLED_CMD);
//--set display clock divide ratio/oscillator frequency
OLED_WR_Byte(0x80,OLED_CMD);
//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD);
//--set pre-charge period
OLED_WR_Byte(0xF1,OLED_CMD);
//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WR_Byte(0xDA,OLED_CMD);
//--set com pins hardware configuration
OLED_WR_Byte(0x12,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);
//--set vcomh
OLED_WR_Byte(0x30,OLED_CMD);
//Set VCOM Deselect Level
OLED_WR_Byte(0x20,OLED_CMD);
//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);
//--set Charge Pump enable/disable
OLED_WR_Byte(0x14,OLED_CMD);
//--set(0x10) disable
OLED_Clear();
OLED_WR_Byte(0xAF,OLED_CMD);
}
稍微解析一下,因为这个函数里面有嵌套的函数还有一些define定义字没有在这里面出现
上方的部分就是GPIO的初始化,先定义一个结构体,然后使能A端的端口时钟,将要初始化的属性填入结构体中,然后用GPIO_Init函数初始化IO口,GPIO_SetBits函数将端口拉高至高电平
中间的三行代码表示将PA2拉低后200ms再拉高,起到一个软件控制的电平变化作用
下面的一大堆相似的代码OLED_WR_Byte就是往OLED的寄存器里面写数据,目的是启动OLED模块,可以跟着英文来看一下它们的功能,它的函数定义就是通过IIC协议发送数据,发送完这些数据后OLED初始化完毕,就可以正常使用了
2、while函数
一般在初始化完成后,裸机开发的例程紧跟着的就是while函数,在单片机系统中的循环一般是死循环while(1),然后在这里面进行一些指令和操作
先将while函数中的功能函数剖析清楚,一直跟到最后一层代码的前一层代码,一般来说,最后一层代码都是类似下图这种的,有英文的功能说明并且解释得很清晰的这种
while函数中的操作就是函数的主逻辑,一般来讲啊,例程里面就会将大部分的功能给写出来的,但是有部分的用得少的功能就可能没有,这样我们就在所包含的头文件中找到源文件,因为头文件和源文件都是一一对应的,都是头文件声明然后源文件定义,这些用到的头文件在main文件的最上方被包含
3、头文件
头文件最主要的就是两个方面,一个是#define宏定义,另一个就是函数的声明
#define在STM32中可以用来定义端口,定义值,以及定义命令,是很重要的一个关键字,学习过C语言的都知道,#define宏定义的最大的功能就是简洁的替换模式和提高代码复用性,可以在代码多次使用某一个值的情况下,改变该值但不用多次修改多处代码,可以将常用的代码片段封装起来,然后在需要的地方通过宏调用展开这些代码片段,从而避免重复编写相同的代码,提高代码可维护性
一般来说,这些函数的名称都是很标准的英文名称,不会出现什么汉字拼音之类的,并且这些名称一般都言简意赅地将它们的功能表达出来了,遇到不会的直接在网上翻译一下就可以,大概了解这一部分的大概功能以及用其他代码代替的define值,然后就可以追踪到源文件看定义了
4、源文件
在源文件中可以直观地观察函数的实现过程,一般我们大学生学就不要上来就自己写了吧,先把例程读懂,然后会开发就可以了,不说难度比较大,就这个底层的代码量你开发一个项目就要累死了,更别说还学别的了
这里给到了一个oled.c 厂家给的代码都会有注释的,各部分的功能很清楚,适当地往里跟一下,这里进来了I2C_Start这个函数,把这些代码看一下可以帮助我们更好地理解各个协议
比如说这里的I2C_Start,把SDA置高电平再把SCL置高电平,然后延时一下把SDA拉低电平,再延时一下把SCL拉低电平,这就跟我们之前博文中总结的IIC通信里的IIC时序基本单元里的起始条件相同:SCL高电平期间,SDA从高电平切换到低电平,然后SCL拉低等待发送数据 这样就可以在实践中掌握理论,对整个知识系统的完善有一个很好的辅助效果
六、移植程序
将每个裸机程序都调试好了,也正常运行了,这样就可以进行向Rtos的移植了,首先要确定好各个模块的某些功能的优先级,当然这个是可以组合着来的,在Rtos上的程序实现是很自由的,一般要将所有初始化模块放到main函数里面,然后开启任务,按照优先级先后来写到任务函数里面
但是要注意,移植过程不要所有模块直接给揉到一起,要一个一个的移植到Rtos中,再次进行调试,调试成功后再向里面加入其他模块,然后重复上述步骤
还想要深入开发一个更复杂的项目的话,深入地学习FreeRtos有很好地效果,前面我们也说过,FreeRtos是一个很自由的平台,我在项目中所使用到的也只是其中的一部分内容,包括内存管理、时间管理、消息队列等等一系列的知识在当中没有使用,但是对于复杂项目的开发是起到一个至关重要的作用的,所以扩充知识储备也是非常重要的