【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)
希望各位指点!