一些概念
并行通信 一次性一起传,需要引脚比较多,速度快。 串行同行 一个个传,需要引脚比较少,速度较慢
串行通信的通信方式 1、同步(带时钟同步信号),如:SPI,IIC 2、异步(不带时钟同步信号),如:UART,单总线 UART:通用异步收发传输器 USART:通用同步/异步串行接收/发送器
USART USART_SRx 状态寄存器 USART_DR 数据寄存器 USART_BRR波特率寄存器,12位的整数和4位小数
串口初始化
在文件夹system下的usart.c文件里,已经写了串口的初始化及相关函数,可以直接用。 关于使用串口的步骤 1、时钟使能 2、串口复位 3、设置GPIO端口初始化(就是速度,模式,功率那些) 4、串口初始化 5、初始化NVIC 6、使能串口
1、时钟使能。
TX和RX的复用GPIO口是GPIOA 在这里是需要使能两个时钟,USART1和GPIOA的时钟
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
2、串口复位
USART_DeInit(USART1);
在sysytem文件夹下的usart.h文件夹下可以找到对应的函数。
3、GPIO模式配置
(跟之前点灯一样),但是设置的输出输入模式参考那个文档
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
4、串口参数初始化
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
5、初始化NVIC并开启中断
关于NAVIC的一些概念 https://blog.csdn.net/hongliwong/article/details/111034892
高优先级的抢占优先级是可以打断正在进行的低抢古优先级中断的。 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
6、开启中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
7、使能串口
(我的理解就是开串口了)
USART_Cmd(USART1, ENABLE); //使能串口1
完整的初始化代码
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0;
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
}
中断函数
USART_RX_STA 是接收是否结束的标志位
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
OSIntEnter();
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
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;//接收数据错误,重新开始接收
}
}
}
}
OSIntExit();
}
一个别人的解释 http://t.csdn.cn/30Lbe
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res; //定义unsigned char型字符Res
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
//接收中断(接收到的数据必须是0x0d 0x0a结尾)
//这里判断发送接收完成的依据就是串口数据0x0d 0x0a,
//0x0d是CR(carriage return)回车的意思,光标回到最左边,
//0x0a是LF(line feed)换行的意思,光标到达下一行,
//但是在PC上回车和换行是在一起的就是按下回车按键
//当然可以更改程序使用其他进行判断例如使用0x2a也就是*进行结束判断
{
Res =USART_ReceiveData(USART1);//(USART1->DR);
//读取接收到的数据,存放到变量Res中
if((USART_RX_STA&0x8000)==0)
//判断接收是否未完成
//接收完成未清除标志位,还是会不断进入到接收中断,所以使用标志进行判断,
//当接收完成便不会跳入到判断,从而不执行任何指令,空等待
//使用条件判断是否已经接收完数据,这里判断接收完的依据就是收到了0x0a;
//具体判断在后面
{
if(USART_RX_STA&0x4000)
//如果接收到了0x0d,那么再进一步执行是否接收到0x0a的判断
{
if(Res!=0x0a)USART_RX_STA=0;
//没有接收到0x0a那么说明,数据未正确传输或者接收错误,重新开始判断,
//但是这里没有将接收到的数据进行清空,也没有退出接收中断,此程序只是从头开始执行接收判断
else USART_RX_STA|=0x8000;
//接收完成了,收到了0x0a那么标志位USART_RX_STA将会变成0x8000,将不再进行数据检测与存储
}
else
//还没收到0X0D,说明数据还未发送结束继续进行数据的检测与存储
{
if(Res==0x0d)USART_RX_STA|=0x4000;
//收到了数据0x0d,标志位USART_RX_STA变成0x4000
else
{
//如果没有接收到数据0x0d,执行判断是否存储数组已满,已满则重新开始接收
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
//将接收到的数据写进数组,标志位USART_RX_STA与上0X3FFF清除前两位以防止标志位与8000和4000冲突
USART_RX_STA++;
//数组地址加一,向后排
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
//接收数据错误,超出数组大小,又开始接收向数组重新写
}
}
}
}
}
一个数据后会加上0X0D 0X0A,如果接收到了0X0A就表示接收结束,没接收到0X0D就表示接收错误。
实验接收到A,LED0亮,再接收到关。
int main(void)
{
u8 t;
u8 len;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
uart_init(9600); //串口初始化为9600
LED_Init(); //初始化与LED连接的硬件接口
while(1)
{
if(USART_RX_STA&0x8000) //接收未完成
{
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
printf("\r\n您发送的消息为:\r\n");
for(t=0;t<len;t++)
{
//USART1->DR=USART_RX_BUF[t];
USART_SendData(USART1, USART_RX_BUF[t]); //向串口1发送数据
while((USART1->SR&0X40)==0);//接收到了0X40就发送结束
}
printf("\r\n\r\n");//插入换行
USART_RX_STA=0;
}else{ //接收完成
u16 res;
res = USART_ReceiveData(USART1);
if(res == '2'){
LED0 = !LED0;
delay_ms(10);
}
if(res == 'B'){
LED1 = !LED1;
delay_ms(10);
}
if(res == 'X'){
LED1 = 1;
LED0 = 1;
delay_ms(10);
}
}
}
}
|