【STM库应用】stm32 之 USART

最后更新于:2022-04-01 14:50:58

STM库是官方提供的,其已经做好了底层驱动的配置,用起来是相当简单的;我们只需要了解其每个函数的功能,已经每个函数所使用流程即可! 整个框架就是下面这幅图,我们只需在顶层做调用即可,跟现在做app的差不多! ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576915b913574.jpg) 注:摘自野火,希望大哥不要说我盗版 刚刚开始拿道库,一看这么多函数,感觉有点棘手,无从下手;多亏stm官方也针对该库提供了一个应用手册,画了两天时间进行了探索和实践,发现了一点比较方便的诀窍。 在此给大家分享分享,我们就拿今天的USART来说吧! 至于建工程,网上以及教程里面是非常多的,我也就不多说了! 任意一个外设都对应一个ppp.c和ppp.h文件,所以我们其实也不是无章可循的!同时,stm库他有一套自己的缩写定义,我们必须记住,不过这个很好记! ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576915b935cc0.jpg) 同时他的函数命名也有一定的规则: 名为PPP_Init的函数,其功能是根据PPP_InitTypeDef中指定的参数,初始化外设PPP,例如  TIM_Init.  名为PPP_DeInit的函数,其功能为复位外设PPP的所有寄存器至缺省值,例如  TIM_DeInit.  名为PPP_StructInit的函数,其功能为通过设置PPP_InitTypeDef 结构中的各种参数来定义外设的功能,例如:USART_StructInit 名为PPP_Cmd的函数,其功能为使能或者失能外设PPP,例如:  SPI_Cmd.  名为PPP_ITConfig的函数,其功能为使能或者失能来自外设PPP某中断源,例如:  RCC_ITConfig.  名为PPP_DMAConfig的函数,其功能为使能或者失能外设PPP的DMA接口,例如:TIM1_DMAConfig.  用以配置外设功能的函数,总是以字符串“Config”结尾,例如GPIO_PinRemapConfig.  名为PPP_GetFlagStatus的函数,其功能为检查外设PPP某标志位被设置与否,例如:I2C_GetFlagStatus.  名为PPP_ClearFlag的函数,其功能为清除外设PPP标志位,例如:I2C_ClearFlag.  名为PPP_GetITStatus的函数,其功能为判断来自外设PPP的中断发生与否,例如:I2C_GetITStatus.  名为PPP_ClearITPendingBit 的函数 , 其功能 为 清除外 设PPP 中断待处理标志位,例如:I2C_ClearITPendingBit.  这些在官方给的库说明里面都有,我只是特别说明下,有助于我么了解! 我们经常用的不多,如:PPP_Init,PPP_Cmd,PPP_ITConfig,PPP_DMAConfig,PPP_GetFlagStatus,PPP_ClearFlag 同时我们需要熟悉的结构体:PPP_InitTypeDef等 上面指出的都是常用的,不多6个函数,1个结构体,相信大家应该能很快记住,我比较笨,记了两天才记的还不是很清! 下面我们先把USART1d的代码附上去! ~~~ void usart_config() { USART_InitTypeDef usart; NVIC_InitTypeDef nvic; RCC->APB2ENR |= 1<<2; RCC->APB2ENR |= 1<<14; GPIOA->CRH &= ~(0xff<<4); GPIOA->CRH |= 0x8b<<4; usart.USART_BaudRate = 9600; usart.USART_Parity = USART_Parity_No; usart.USART_StopBits = USART_StopBits_1; usart.USART_WordLength = USART_WordLength_8b; usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(USART1,&usart); USART_Cmd(USART1,ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); nvic.NVIC_IRQChannel = USART1_IRQn; nvic.NVIC_IRQChannelCmd = ENABLE; nvic.NVIC_IRQChannelPreemptionPriority = 0x0f; nvic.NVIC_IRQChannelSubPriority = 0x0f; NVIC_Init(&nvic); USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); } ~~~ 怎么说呢,我是比较懒的!所以我比喜欢别人那种命名变量的方式,我以前是做linux的,我喜欢linux那套命名模式! 另外,我建议大家在做开发的时候用Keil4.0以上的版本,为啥呢?下面正式我想说的 我们在声明一个结构体变量的时候,我们不知道结构题里面每个变量的名字,怎么办?找吗?很麻烦是吧? 如果我们用了mdk4.0以上的版本,他会自动匹配 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576915b9542a2.jpg) 可能有的人用过了,会说我多余,呵呵但是对那些没有用过的人很有用,比如李想老师!呵呵,开个玩笑 这样我们就不用一个一个输入了!但是后面的变量赋值怎么办?其实这些变量赋值都在ppp.h里面定义好了,我大致看了下ppp.h内容不是很多,所以很容易就找到,我有一个方法就是查找! 比如我们要找USART_Mode所对应的赋值: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576915b96c156.jpg) 切换到stm32f10x_usart.h,直接在上面输入USART_Mode,按下Enter键,就找到了,那么我就直接把这个定义赋值过去,好了! 有人说我函数名记不住,那么我们还是在stm32f10x_usart.h直接一下子拉到最下面!是不是看到了所有的函数? ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576915b987764.jpg) 如果你细心看我代码的话,你会发现,我对GPIO的初始化没有用结构图,我发现直接配置管脚的话很方便,代码不多,我4行能解决他十几行的代码! RCC->APB2ENR |= 1<<2; RCC->APB2ENR |= 1<<14; GPIOA->CRH &= ~(0xff<<4); GPIOA->CRH |= 0x8b<<4; 这样就把整个配置完了!有的人说我能记住吗?这么多位!我只想呵呵!不信你自己对着寄存器看下 比如输入模式:后两位一定是00b,输出模式一定是其他三种!在输出中00,01为通用,10,11为复用,偶数为推挽,奇数为开漏,好记吧? 在输入中,有三种模式,浮空就是复位的时候,还有模拟输入,还有上拉下拉输入! 我今天想写中断函数,怎么办?记不住啊,我想既然是中断函数,他一定在启动代码里面有定义,直接切换到startup_stm32f10x.md.s里面,直接搜索Handler 找到所有中断函数的定义: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576915b9ab41e.jpg) 有了这些基本思想,我们在写程序的时候方便多了,这次完成串口的配置就用了半个小时!我只能说库用着好方便! ~~~ /***************************************** * @file obj/main.c * @author ieczw * @version V1.0.1 * @date 24-11-2013 *****************************************/ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" #include "stdio.h" #include "stm32f10x_conf.h" void usart_config(void); void led_init(void); void msleep(u16 timeout); void rs232_send_byte(u8 byte); u16 systick = 0; int main(void) { u8 ascii = 0; SysTick_Config(72000); //Config DiDa = 1ms /* Add your application code here */ usart_config(); led_init(); /* Infinite loop */ GPIOC->BRR |= 0xff<<8; msleep(1000); GPIOC->BSRR |= 0xff<<8; while (1) { rs232_send_byte(ascii++); msleep(1000); } } void led_init() { RCC->APB2ENR |= 3<<4; GPIOC->CRH = 0x33333333; GPIOD->CRL &= ~(0xf<<2); GPIOD->CRL |= 3<<2; GPIOD->ODR &= ~(1<<2); GPIOC->ODR |= 0xff<<8; } void usart_config() { USART_InitTypeDef usart; NVIC_InitTypeDef nvic; RCC->APB2ENR |= 1<<2; RCC->APB2ENR |= 1<<14; GPIOA->CRH &= ~(0xff<<4); GPIOA->CRH |= 0x8b<<4; usart.USART_BaudRate = 9600; usart.USART_Parity = USART_Parity_No; usart.USART_StopBits = USART_StopBits_1; usart.USART_WordLength = USART_WordLength_8b; usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(USART1,&usart); USART_Cmd(USART1,ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); nvic.NVIC_IRQChannel = USART1_IRQn; nvic.NVIC_IRQChannelCmd = ENABLE; nvic.NVIC_IRQChannelPreemptionPriority = 0x0f; nvic.NVIC_IRQChannelSubPriority = 0x0f; NVIC_Init(&nvic); USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); } void rs232_send_byte(u8 byte) { USART_SendData(USART1,byte); while(RESET == USART_GetFlagStatus(USART1,USART_FLAG_TXE)); } void USART1_IRQHandler(void) { static u8 flag = 0; flag = ~flag; if(flag) GPIOC->BRR |= 0xff<<8; else GPIOC->BSRR |= 0xff<<8; if(USART1->SR&(1<<5)) { USART1->DR = USART1->DR; while(0 == (USART1->SR&(1<<6))); } } void msleep(u16 timeout) { systick = timeout; while(systick); } ~~~ 今天就是说库如何使用,原理请看[http://blog.csdn.net/ieczw/article/details/16118387](http://blog.csdn.net/ieczw/article/details/16118387) 希望各位指点!
';