STM32固件库学习方法
更新时间:2024-03-26 23:19:01 阅读量: 综合文库 文档下载
STM32学习教程
教程一
1、一共24个库,不可能都学,都学也没用。主要学习来源是各种例程代码,固件库函数用户手册和参考手册。
具体学习方法是通读不同来源的程序,在程序中找到相关的函数库的应用,然后再阅读相关文档,有条件的实验。对于内容的选择方面,根据入门内容和未来应用,将所涉及的范围精简到最低,但是对选择的部分的学习则力求明确。,以下是按照自己的需求对程序库函数排列的学习顺序:
A、 绝大部分程序都要涉及到的库——flash、lib、nvic、rcc,学习基础的跟简单应用相关比
用的部分,其它部分后期再返回头学。
B、各种通用但不必用的库——exit、MDA、systic,通读理解其作用。 C、DEMO板拥有的外设库——gpio、usart,编写代码实验。
D、未来需要用到的外设库——tim、tim1、adc、i2c,spi,先理解待有条件后实验。 E、开发可靠性相关库——bkp、iwdg、wwdg、pwr F、其它,根据兴趣来学。
2、阅读flash
芯片内部存储器flash操作函数:对芯片内部flash进行操作的函数,包括读取,状态,擦除,写入等等,可以允许程序去操作flash上的数据。
基础应用1
Flash时序延迟几个周期,等待总线同步操作。推荐按照单片机系统运行频率,0-24MHz时,取Latency=0;24-48MHz时,取Latency=1;48~72MHz时,取Latency=2所有程序中必须的.用法:FLASH_SetLatency(FALSH_latency_2);
位置:RCC初始化子函数里面,时钟起振之后。
基础引用2
开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的。 用法:FALSH_PrefetchBufferCmd(FALSH_PrefetchBuffer_Enable); 位置:RCC初始化子函数里面,时钟起振之后。
3、阅读lib
调试所有外设初始化的函数。
只需要知道外设在调试的时候,EWRAM需要从这个函数里面获得调试所需信息的地址或指针之类的信息。
基础应用1
只有一个函数debug。所有程序中必须的。 用法: #ifdef DEBUG debug();
#endif
位置:main函数开头,申明变量之后。
4、阅读nvic,系统中断管理
管理系统内部的中断,负责打开和关闭中断。
基础应用1,中断的初始化函数
包括设置中断向量表位置,开启所需的中断两部分。所有程序中必须的。
用法:如果定义了VECT_TAB_RAM,则在RAM中调试,没定义,在Flash中调试。 void NVIC_Configuration(void) {
NVIC_InitTypeDef NVIC_InitStructure; //中断管理恢复默认参数 #ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VecTab_RAM,0x0); #else
NVIC_SetVectorTable(NVIC_VecTab_FLASH,0x0); #endif
//下面为中断的开启过程,不是所有程序必须的 //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC优先级分组方式
//一共有16个优先级,分为抢占式和响应式。两种优先级所占有的数量由此代码确定。//NVIC_PriorityGroup_x可以是0、1、2、3、4,分别代表抢占优先级有1、2、4、8、16个//和响应优先级有16、8、4、2、1个。规定两种优先级的数量后,所有的中断级别必须在//其中选择,抢占级别高的会打断其它中断优先执行,而响应级别高的会在其它中断执行完//优先执行。
//NVIC_InitStructure.NVIC_IRQChannel=中断通道名;
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriorit=0; //抢占优先级 //NVIC_InitStructure.NVIC_IRQChannelSubPriorit=0; //响应优先级
//NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //启动此通道的中断 //NVIC_Init(&NVIC_InitStructure); //中断初始化 }
5、阅读rcc:时钟管理
管理外部、内部和外设的时钟,设置、打开和关闭这些时钟。
基础应用1:
时钟的初始化函数过程: 用法:
void RCC_Configuration(void) {
ErrorStatus HSEStartUpStatus; //等待时钟的稳定
RCC_DeInit(); //将时钟重置为缺省值 RCC_HSEConfig(RCC_HSE_ON); //设置外部晶振 HSEStartUpStatus=RCC_WaitForHSEStartUp(); //等待外部晶振就绪 If(HSEStartUpStatus==SUCCESS) {
FALSH_PrefetchBufferCmd(FALSH_PrefetchBuffer_Enable); //使能预取缓存 FLASH_SetLatency(FLASH_Latency_2); //FALSH操作的延时 RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB使用系统时钟 RCC_PCLK2Config(RCC_HCLK_Div2); //APB2为HCLK的一半 RCC_PCLK1Config(RCC_HCLK_Div2); //APB1为HCLK的一半
RCC_PLLConfig(RCC_PLLSAource_HSE_Div1,RCC_PLLMul_9);//PLLCLK=8MHz*9=72MHz RCC_PLLCmd(ENABLE); //启动pll while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)
{} //等待PLL启动
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //将PLL设置为系统时钟源 While(RCC_SYSCLKSource()!=0x80)
{} //将PLL返回,并作为系统时钟源
}
//RCC_AHBPeriphClockCmd(AHB2设备1|AHB2设备2,ENABLE); //启动AHP设备 //RCC_APB2PeriphClockCmd(ABP2设备1|ABP2设备2,ENABLE); //启动abp2设备 //RCC_APB1PeriphClockCmd(ABP1设备1|ABP1设备2,ENABLE); //启动abp1设备 }
6阅读exti:外部设备中断函数
外部设备通过引脚给出的硬件中断,也可以产生软件中断,19个上升、下降或都触发。EXTI0~EXTI15连接到管脚,EXTI线16连接到PVD(VDD监视),EXTI线17连接到RTC(闹钟),EXTI线18连接到USB(唤醒)。
基础应用1:设定外部中断初始化函数。按需求,不是必须代码。 用法:
Void EXTI_Configuration(void) {
EXTI_InitTypeDef EXTI_InitStructure; //外部设备中断恢复默认参数 EXTI_InitStructure.EXTI_Line = EXTI_Line12 | EXTI_Line14; //设定所需产生中断的通道,共19个 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置中断模式 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //启动中断的接收 EXTI_Init(&EXTI_InitStructure); //外部设备中断启动
}
图中在第4步根据中断屏蔽寄存器中的设定判别发生了哪一个中断,然后将该信号发送给NVIC(增强型可屏蔽中断控制器),NVIC根据信号将相应的中断函数的地址赋予PC要调用的寄存器,这样Cortex-M3将执行对应的中断函数。 用户在使用中无需通过头文件定义,在软件库3.1.2中的startup_stm32f10x_??.s文件中对中断函数的地址进行了宏定义,用户只需根据startup_stm32f10x_??.s中的PPP_IRQHandler,在stm32f10x_it.c和stm32f10x_it.h中添加相应的void PPP_IRQHandler(void) 函数,并在.c中添加中断处理代码即可。
对于EXTI9_5_IRQHandler和EXTI15_10_IRQHandler中断用户需要在处理函数中通过ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)来判别发生了哪一个中断,再进行相应的处理。
7、阅读dma
通过总线而越过CPU读取外设数据
通过DMA应用可以加速单片机外设、存储器之间的数据传输,并在传输期间不影响CPU进行其他事情。这对于入门卡法基本功来说,没有太大必要,这个内容先行跳过。
8、阅读systic:系统定时器
可以输出和利用系统时钟的计数、状态
基础应用一,精确计时的延时子函数。推荐使用的代码。
Static vu32 TimingDelay; //全局变量申明 Void SysTick_Configuration(void) {
SysTick_CounterCmd(SysTick_Counter_Disable); //停止系统定时器 SysTick_ITConfig(Disable); //停止systick中断
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_DIV8); //HCLK作为时钟源,频率值/8 SysTick_SetReload(9000); //重置时间1毫秒,以72MHz为基础计算 SysTick_ITConfig(Enable); //开启systic中断 }
void Delay(u32 nTime) //延迟一毫秒的函数 {
SysTick_CounterCmd(SysTick_Counter_Enable); //systic开始计时
TimingDelay=nTime; //计时长度赋值给递减变量 while(TimingDelay!=0); //检测是否计时完成 SysTick_CounterCmd(SysTick_Counter_Disable); //关闭计数器 SysTick_CounterCmd(SysTick_Counter_Clear); //清楚计数值 }
Void TimingDelay_Decrement(void) //递减变量函数,函数名由“stm32f10x_it.c”中的中断
//相应函数定义好了
{
If(TimingDelay!=0x00) TimingDelay--; }
新手可用简化的延时函数代替: Void Delay(vu32 nCount) {
For(;nCount!=0;nCount--); }
当延时较长,又不需要精确计时的时候可以使用嵌套循环: Void Delay(vu32 nCount) {
Int i;
for(;nCount!=0;nCount--) For(i=0;i<0xffff;i++); }
9、基本硬件功能的建立
flash、lib、nvic、rcc和gpio,基础程序库编写
这几个库函数中有一些函数是关于芯片的初始化的,每个程序中比用。为保证程序品质,初学阶段要求严格遵守官方习惯。注意,官方程序库例程中有个platform_conf.h文件,是专门用来指定同类外设中第几号外设被使用,就是说在main.c里面所有外设程序号用x代替,比如USARTx,程序会到这个头文件中去找到底是用那些外设,初学的时候参考例程别被这个所迷惑。
全部比用代码取自函数库所带例程,并增加主句注释。 习惯顺序:lib(debug),RCC(包括flash优化),NVIC,GPIO 必用模块初始化函数的定义:
void RCC_Configuration(void); //定义时钟初始化函数 void GPIO_Configuration(void); //定义管脚初始化函数 void NVIC_Configuration(void); //定义中断管理初始化函数 void Delay(vu32 nCount); //定义延迟函数 main中的初始化函数调用: RCC_Configuration();
GPIO_Configuration(void); NVIC_Configuration(void);
Lib注意事项:
属于lib的Debug函数的调用,应该放在main函数最开始,不要改变其位置。 RCC注意事项:
Flash优化处理可以不做,但是两句也不难,也不用改参数。。。。。。 根据需要开启设备时钟可以节省电能 时钟频率需要根据实际情况设置参数 NVIC注意事项:
注意理解占先优先级和响应优先级的分组概念 GPIO注意事项:
注意以后的过程中收集不同管脚对应的频率和模式的设置。 作为高低电平的I/O,所需设置:RCC初始化里面打开
10、基本串口通讯
初始化函数定义、调用:
Void USART_Configuration(void); //定义初始化函数 初始化代码:
Void USART_Configuration(void) {
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_Odd;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_InitStructure.USART_Clock = USART_Clock_Disable; USART_InitStructure.USART_CPOL = USART_CPOL_High; USART_InitStructure.USART_CPHA = USART_CPHA_1Edge; USART_InitStructure.USART_LastBit = USART_LastBit_Enable; USART_Init(USART1, &USART_InitStructure); //初始化
USART_Cmd(USART1,ENABLE); //启动串口 }
RCC中打开相应串口
RCC_APB2Perph kCmd(RCC_APB2Perph_USART1,ENABLE);
GPIO里面设定相应的串口管脚模式:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //配置为复用推挽输出 GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //LED2, LED3 V7 V8 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure);
简单应用:发送一位字符
USART_SendData(USART1,数据); //发送一位数据
whlie(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET){} //等待发送完毕 接收一位字符
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET){} //等待接收完毕 变量=USART_ReceibeData(USART1); //接收一个字节
发送一个字符串
先定义字符串:char rx_data[250];然后再需要发送的地方添加如下代码
Int i; //定义循环变量
while(rx_data!=’\\0’) //循环逐字输出,到结束字‘\\0’ {
USART_SendData(USART1,rx_data);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET){} i++; }
USART 注意事项:
发送和接收都需要配合标志等待。
只能对一个字节操作,对字符串等大量数据操作需要写函数 使用串口所需设置:
RCC初始化:RCC_APB2PeriphClockCmd(Rcc_APB2Periph_USARTx);
GPIO里面管脚设定:串口RX(50Hz,IN_FLOATING);串口TX(50Hz,AF_PP); printf函数重定义(不必理解,调试通过后备用) (1)需要c标准函数: #include “stdio.h” (2)粘贴函数定义代码
#define PUTCHAR_PROTOTYPE int _io_putchar(int ch) //定义为putchar应用 (3)RCC中打开相应串口
(4)GPIO里面设定相应串口管脚模式 (5)增加为putchar函数 int putchar(int c) {
If(c==’\\n’)
{putchar(‘\\r’);}
USART_SendData(USART1,c);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET){} renturn c; }
(6) printf使用的变量输出:%c 字符,%d整数,%f浮点数,%s字符串,/n或/f为换行。注意,只能用于main.c中。
NVIC串口中断的应用
在实际应用中,不使用中断进行的输入,效率是非常低的,这种用法很少见,大部分串口的输入都离不开中断。
初始化函数定义及函数调用:不用添加和调用初始化函数,在指定调试地址的时候已经调用过,在那个NVIC_Configuration里面添加相应中断代码就行了。 过程:
(1)串口初始化中USART_Cmd之前加入中断设置:
USART_ITConfig(USART1,USART_IT_TXE,ENABLE); //TXE发送中断,TC传输完成中断,
//RXNE接收中断,PE奇偶错误中断,可以是多个
(2)RCC、GPIO里面打开串口相应的基本时钟、管脚设置 (3)NVIC里面加入串口中断打开代码;
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel; //串口1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中断占先级0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中断相应优先级0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打开中断 NVIC_InitStructure(&NVIC_InitStructure); //初始化
(4)在stm32f10x_it.c文件中找到void USART1_IRQHandler函数,在其中添加执行代码。一 般最少三个步骤:先使用if语句判断是发生那个中断,然后清除中断标志位,最后给字符串符 赋值,或做其它事情。 Void USART1_IRQHandler(void) {
Char RX_dat;
If(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //判断是否收到中断 {
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志 GPIO_WriteBit(GPIOB,GPIO_P_10,(BitAction)0x01); //开始传输
RX_dat=USART_ReceiveData(USART1)&0X7F; //接收数据并除去第一位 USART_SendData(USART1,RX_dat); //发送数据 while(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET){}
} }
(5)中断注意事项:
可以随时在程序中使用USART_ITConfig(USART1,USART_IT_TXE,DISABLE);来关闭中断相应。 NVIC_InitTypeDef NVIC_InitStructure定义一定要加在NVIC初始化模块的第一句。 全局变量于函数的定义:在任意.c文件中定义的变量或函数,在其他.c文件中使用extern+ 定义码再次定义就可以直接调用了。
STM32F100X RCC_APB2Periph_AFIO--复用IO时钟的使用
为了优化64脚或100 脚封装的外设数目,可以把一些复用功能重新映射到其他引脚上。设置复用
重映射和调试I/O 配置寄存器(AFIO_MAPR) 实现引脚的重新映射。这时,复用功能不再映射到它
们的原始分配上。
需要用到外设的重映射功能时才需要使能AFIO的时钟
外部中断(EXTI)中与AFIO有关的寄存器是AFIO-EXTICR1、2、3,它们是用来选择EXTIx外部中断的输入脚之用。 举例:重映射USART2
USART2的TX/RX在PA.2/3
但是,PA.2已经被Timer2的channel3使用 这时,如果还想使用USART2,但又不想影响Timer2的使用,这就需要把USART2的TX/RX重映射到PD.5/6。 映射库函数的调用过程
(1)使能被重新映射到的I/O端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
(2)使能被重新映射的外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); (3)使能AFIO功能的时钟(勿忘!)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); (4)进行重映射
GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
用库函数使用SYSTICK的方法
Systick配置函数
延迟一毫秒函数
中断调用函数
中断进入函数
Q:什么是SYSTick定时器?
SysTick 是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
Q:为什么要设置SysTick定时器?
(1)产生操作系统的时钟节拍
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 (2)便于不同处理器之间程序移植。
Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。 不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3产品间对其处理都是相同的。
(3)作为一个闹铃测量时间。
SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。
Q:Systick如何运行?
首先设置计数器时钟源,CTRL->CLKSOURCE(控制寄存器)。设置重载值(RELOAD寄存器),清空计数寄存器VAL(就是下图的CURRENT)。置CTRL->ENABLE位开始计时。
如果是中断则允许Systick中断,在中断例程中处理。如采用查询模式则不断读取控制寄存器的COUNTFLAG标志位,判断是否计时至零。或者采取下列一种方法
当SysTick定时器从1计到0时,它将把COUNTFLAG位置位;而下述方法可以清零之:
1. 读取SysTick控制及状态寄存器(STCSR) 2. 往SysTick当前值寄存器(STCVR)中写任何数据 只有当VAL值为0时,计数器自动重载RELOAD。
Q:如何使用SysTicks作为系统时钟?
SysTick 的最大使命,就是定期地产生异常请求,作为系统的时基。OS都需要这种“滴答”来推动任务和时间的管理。如欲使能SysTick异常,则把STCSR.TICKINT置位。另外,如果向量表被重定位到SRAM中,还需要为SysTick异常建立向量,提供其服务例程的入口地址。
正在阅读:
STM32固件库学习方法03-26
现在完成时讲义习题以及答案05-29
中山大学宏观经济学4 (2)06-01
出现自动配置IPv4地址169.254.x.x首选地址-地址冲突造成08-06
二年级数学下册 租船 3教案 北师大版05-08
诚信库申报操作手册05-03
财政学(详细版)12-29
铝液外运应急预案07-10
腰筋拉筋心法总诀01-14
区域金融生态环境面临的问题及对策04-22
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 固件
- 学习方法
- STM32
- 3 立题目的与依据
- 平行四边形的性质课堂教学实录
- 中型轴承套料锻造线项目可行性研究分析报告-甲级资质
- 2013年最新建筑工程管理与实务重点归纳总结
- UG功能技巧总结 - 图文
- 在美术世界中遨游说课稿
- 苏教版七年级上册数学知识点总结 - 图文
- 11年7中初三一模语文试题及答案
- 毛泽东关于党的批评与自我批评优良作风思想论纲
- 2017年德城区第一次中考练兵考试 生物试题
- 浙江2018年高中物理第十六章动量守恒定律第5节反冲运动火箭学案
- 中信建投证券风险揭示书
- 数据库复习题
- 2015会计从业《财经法规》上机题库第四章财政法规制度doc
- 某养殖小区规划设计方案
- 对供给学派的经济理论和政策主张的批判
- 广东省化妆品安全条例信息
- 2016-2022年中国装备制造业信息化行业深度研究与投资前景预测报
- 中考新突破中考英语话题二十二科普知识与现代技术试题
- 余额宝的营销调查报告毕业论文