STM32开发中各库函数的主要作用和关系
STM32各库函数关系的简单解析
您好! 这是我第一次使用 CSDN来发布文章, 如果有排版不合理,结构凌乱,欢迎私信我交流经验。文章内容如有错误,欢迎读者指正!
首先我们了解一下什么是库函数?
众所周知,芯片本身仅仅是一种硬件,没有软件的加持,无法完成某种特定功能。我们通过电脑编写程序烧录入芯片后,芯片便有了某种功能。在对于微控制器来说,目前主流芯片便是51和STM32,51由于是8位处理器,所以通过寄存器进行程序编写是可行的,但是32位处理器因为寄存器数量庞大,数据手册动辄上千页,这么多的寄存器要去吃透它,在难度和时间上面肯定不允许。但有了库函数以后,会让我们的开发效率大大提高。这一点非常重要,毕竟做项目的时间是非常有限的,如果要去研究寄存器的使用,那真是费时又费力,作为工程师来说,我们当然希望操作越简单越好了,如果是傻瓜式的操作那更好。库函数的使用让我们不需要去了解硬件的机制,只要根据功能去找到相应的操作函数就好了,大大降低了开发要求。
有了库函数还需要学习寄存器的操作吗?
作为一个从事底层软件开发的人,我认为还是有必要更加了解硬件的。用了库函数的缺点就是,代码量会增大,库函数会把所有情况都考虑到函数里面,有时会造成代码的冗余,在程序空间吃紧的时候,你还是得乖乖优化成寄存器的方式。对于一些实时性要求极其严格的场合,直接操作寄存器无疑是更好的选择。对于学习而言,打好寄存器的基础会让你使用库函数时事半功倍。
对于想要了解寄存器的读者,推荐大家下面几个文件,都是在学习寄存器时必不可少的文件。由于版权问题,不便直接上传文件,网上资源还是很好找的,大家随便找找都找的到。
- STM32F10x参考手册-V9
- STM32F10x闪存编程手册
- STM32固件库使用手册
- ARM Cortex-M3权威指南(第2版);
下面我将介绍主要库函数文件的关系
- stm32f10x.h
这个文件可以说是最重要的文件之一,无论是寄存器开发还是库函数开发,此文件都是必不可少的。文件中定义了系统寄存器的地址以及使用结构体封装,定义声明以及包装内存操作。 此文件中还包含stm32f10x_conf.h,这个文件在下一个中细讲。 stm32f10x.h中定义了启动设置,以及所有寄存器宏定义,此文件中需要注意的有: 1、device选择;2、外部时钟频率选择;3、外设宏定义USE_STDPERIPH_DRIVER;
各种寄存器的地址(仅仅截取了极小的一部分),有兴趣的可以打开源文件自己看一下 文件中还包含stm32f10x_conf.h
- stm32f10x_conf.h
stm32f10x_conf.h中包含了所有外设的头文件,因此任意源文件只要包含了stm32f10x.h,就可以在源文件调用任意外设的函数,而不需要的外设部分,可以在stm32f10x_conf.h中注释掉,项目编译时就不会再编译以及去掉的外设。 至此,基本的库函数文件就都被包含进来了。 - stm32f10x_it.c和stm32f10x_it.h
文件中包含了所有中断服务函数 中断是嵌入式系统中重要的组成部分,但是在标准C中不包含中断。许多编译开发商在标准C上增加了对中断的支持,提供新的关键字用于标示中断服务程序 (ISR),类似于__interrupt、#program interrupt等。当一个函数被定义为ISR的时候,编译器会自动为该函数增加中断服务程序所需要的中断现场入栈和出栈代码。 中断服务程序需要满足如下要求: (1)不能返回值; (2)不能向ISR传递参数; (3) ISR应该尽可能的短小精悍; (4) printf(char * lpFormatString,…)函数会带来重入和性能问题,不能在ISR中采用。
a.为什么不能有返回值?
中断服务函数的调用是硬件级别的,当中断产生,pc指针强制跳转到对应的中断服务函数入口,进入中断具有随机性,并不是某段代码对其进行调用,那么如果有返回值它的返回值返回给谁?显然这个返回值毫无意义,如果有返回值,它必定需要进行压栈操作,这样一来何时出栈怎么出栈将变得无法解决。
b.不能向ISR传递参数?
同理,也是由于这样会破坏栈的原因,因为函数传递参数必定会要求压栈出栈操作,由于进入中断服务函数的随机行,谁给它传递参数都成问题
c.ISR应尽可能的短小精悍?
如果某个中断频繁产生,而它对应的ISR相当的耗时,那么对中断的响应就会无限的延迟,会丢掉很多的中断请求
d.printf(char * lpFormatString,…)函数会带来重入和性能问题,不能在ISR中采用。
这就涉及到一个中断嵌套问题,由于printf之类的glibc函数采用的是缓冲机制,这个缓冲区是共享的,相当于一个全局变量,第一层中断来时,它向缓冲里面写入一些部分内容,恰好这时来了个优先级更高的中断,它同样调用了printf,也向缓冲里面写入一些内容,这样缓冲区的内容就错乱了。
实际上,中断服务函数的函数名,是已经被强制定义过的,我们无法更改,只能使用。具体内容在启动文件 startup_stm32f10x_hd.s 之中,(芯片不同启动文件名称不同)。
一小部分中断服务函数,有兴趣的可以打开源文件自己看一下。 在使用中断服务函数时,我们只需要编写中断服务函数的具体内容便可,以串口1的中断服务函数为列。
void USART1_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1);
if((USART_RX_STA&0x8000)==0)
{
if(USART_RX_STA&0x4000)
{
if(Res!=0x0a)USART_RX_STA=0;
else USART_RX_STA|=0x8000;
}
else
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
}
}
}
}
- system_stm32f10x.c和 system_stm32f10x.h
设备外设访问层,主要配置时钟频率(设置系统以及总线时钟)
|