姓名:徐予康 学号:19020100223 学院:丁香二号书院
转自:https://blog.csdn.net/peipanbryant/article/details/105610240
【嵌牛导读】嵌入式的学习避免不了c语言的学习,本文介绍了一些嵌入式开发中c语言的基础知识点
【嵌牛鼻子】static和extern变量 continue和break FIFO和软件定时器
【嵌牛提问】嵌入式学习的c语言,你需要了解一些什么?
【嵌牛正文】
c程序小知识点总结
1.静态变量static与外部变量extern的使用
静态变量static两种使用方式
一.定义局部变量
用static声明后的局部变量的值在函数调用结束后不消失而保持原值,其占用的是静态存储区,所以即其占用的存储单元不释放。典型应用是用static变量求阶乘n!。
2.这样声明的变量,其存储在程序的bss段,而在bss段在程序中执行时会初始化为0.
// eg:
static int b[5] ;
//则b[0] = 0 ,b[1] = 0等等. 而如果不是这样定义则输出可能是乱码
二.定义全局变量
当定义全局变量只限于本文件使用,而不被其他文件使用,这时可以在定义外部变量的时候加一个static声明。注意定义加了static和不加的外部变量都是存放在静态存储区,而区别就在于上一句的“只限于本文件使用”。
外部变量extern
作用:声明外部变量,扩展它在程序文件中的作用域。即在文件1定义的全局变量int A,可以在文件2中定义 extern A ,便可调用这个文件1中的全局变量。比如在实际具体工程项目中,在定时器文件中定义的全局变量时间int32_t g_iRunTime ,最长可以表示 24.85天,也就是你的终端可持续运行的时间,在其他项目其他文件中,像主函数文件中也需调用用于判断运行时间则就用extern g_iRunTime调用。
2.函数封装后返回值的方法
一. 只需返回一个值得时候
常用的简单方法就是定义函数为有返回值的函数,其函数的类型标识符与返回值得类型一致。
比如 int fun();函数返回就是int类型的数值。
定义一个全局变量,因为全局变量存在于静态存储区,当函数调用的时候改变了全局变量的值,也实现了函数返回值得功能。
二. 要求返回多个值得时候
前两者返回一个值得方法可以共用以达到返回多个值。
在形参中定义一个数组或者指针,并在主函数中定义一个数组来保存返回的值
需要注意的是,一般原则:在程序设计中,再划分模块时要求模块”内聚性”强,与其他模块的“耦合性”弱。简单理解就是,在封装的各个函数中各有自己独立功能,即功能单一,方便调用,而不能搞的太乱。对于全局变量需限制使用。
3.循环控制continue与break的区别
在项目工程当中,或者简单的C语言代码当中,循环使用的非常普遍,掌握循环的各个形式非常重要,这里简单的介绍下循环控制中continue 与 break的区别。
利用代码体现:
//简介循环控制continue与break的区别
main()
{while(表达式一)
{if(表达式二)
{break ; //跳出循环,也即跳出while语句转执行下面的语句}}
while(表达式一)
{if(表达式二)
{continue ; //跳到条件限制,也即跳到while语句判断中}}}
如上面清晰易懂,在写代码当中或者看懂下载得源代码中,如果不是在主函数main中出现的while(1),其他函数中出现while(1),都必然存在一个break语句,在首先学习看懂源代码的任务中,这点比较重要。(看来这点只适合初学者啊,只要有点经验都知道这些浅显的但关键的知识点)
项目程序规范
1.消息队列FIFO
核心思想:通过消息队列机制,在MAIN函数中,通过消息传递任务来执行。 当某一任务需要执行的时候,通知消息队列,主程序去执行。 主程序在函数中解析消息队列,看有无任务。
首先在头文件中定义队列的类型,以及消息队列的尺寸。
建立一个函数:uint8_t MsgtGetMes( Msg_List *_pByte) ,从消息队列中读出一条信息。和一个函数: uint8_t MsgtPushMes( Msg_List *_pByte),写入到队列一条消息。
判断有无任务需要执行(这个时候需要用到软件定时器(下面将具体介绍),每个功能到设置一定的时间去向cpu发送处理数据),将需要执行的任务放入队列函数void AppTaskScan(void),巡检任务。
建立一个 函 数 : vTaskStartScheduler(), 任务调度函数,将消息队列中读出一个任务去执行,先发出信号的任务先执行,如果有一个任务同时触发相同的任务,按队列的先后去执行这依程序。
**至此,**在主函数mian中的while(1)中调用5,6两个函数询检即可。
队列FIFO运用主要是对CPU分配管理:一般的计算机系统只有一个CPU,如果在系统中的多个进程都满足运行条件,这就可以用一个就绪队列来进行管理。当某个进程需要执行的时候,它的进程名就插入到就绪队列的尾端。如果此队列是空的,CPU就立即执行此进程;如果此队列非空,则该进程就需要排在队列的尾端进行等待。CPU总是首先执行排在队首的进程,一个进程分配的一段时间执行完了,又将它插入队尾进行等待,CPU转而为下一个出现在队首的进程服务。如此。按照“FIFO”的原则一直进行下去,直到执行完的进程从队列中删掉。
队列fifo还可用于许多场景,比如串口fifo,多串口运行时的分配。
2.软件定时器的使用
这部分我主要是针对stm32的程序来使用的,首先配置systick定时器作为系统滴答定时器。缺省定时周期为1ms。实现了多个软件定时器供主程序使用(精度1ms), 可以通过修改 TMR_COUNT 增减软件定时器个数。
这部分还是主要为CPU处理队列信息的使用做服务的。为每个单一任务设置定时器,一旦到了设定的时间就像队列写入一个该任务消息,直到CPU处理为止,定时器主要实现任务调度的问题。当然,风格不同的工程师有着不同的用法!
配置systick定时器,周期为1ms
方法:在core_cm3.h有一个这样的函数uint32_t SysTick_Config(uint32_t ticks),该函数的形参表示内核时钟多少个周期后触发一次Systick定时中断
– SystemCoreClock / 1000 表示定时频率为 1000Hz, 也就是定时周期为 1ms
– SystemCoreClock / 500 表示定时频率为 500Hz, 也就是定时周期为 2ms
– SystemCoreClock / 2000 表示定时频率为 2000Hz, 也就是定时周期为 500us
所以我们一般在定时器初始化函数中调用SysTick_Config(SystemCoreClock / 1000);形成周期性中断函数每一ms执行中断一次,即需要中断就要写了个中断服务程序void SysTick_Handler(void);该函数主要为下面制定软件定时器的计数每隔1ms进行减一操作。
软件定时器的设置
1.定义定时器结构体以及定时器的个数和各个任务定时器的名称
typedef struct
{
volatile uint8_t Flag; /* 定时到达标志 */
volatile uint32_t Count; /* 计数器 */
volatile uint32_t PreLoad; /* 计数器预装值 */
}SOFT_TMR;
/* 软件定时器个数 */
#define TMR_COUNT 5 //自己设定需要多少软件定时器
/*定义定时器名称*/
#define C_TMR_ID (4)
#define C_TMR_ID (3)
#define E1_TMR_ID (2)
#define E_TMR_ID (1)
#define cTMR_ID (0)
现在主要写两个函数 一个:void bsp_StartAutoTimer(uint8_t _id, uint32_t _period)主要是将设定的实时计数器初值period的值装入结构体中,利用定时器中断服务程序自减一,并到减到0时Flag置为1,在另一个函数uint8_t bsp_CheckTimer(uint8_t _id)中判断Flag定时到达标志是否定时时间到了,返回1.用于void AppTaskScan(void)巡检判断任务。
版权声明:本文为CSDN博主「peipan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。