列表 上一篇 下一篇

STM32:中断模式USART实验1

先上代码

/* 1.串口输出提示信息 2.串口等待接收数据,收到尾子符或者缓冲区满则不再接收数据并开启发送中断,准备发送数据,进入3 3.串口发送完刚才接收到的数据之后,开启接收中断,等待接收数据,进入2 */ #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_usart.h" #include "misc.h" #define BUFF_MAX 100 //缓冲区最大容量 int sendindex=0;//发送数据索引 int recvindex=0;//接收数据索引 char info[]="please input,end with a *"; char buffer[BUFF_MAX]; int main() { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_Init(&NVIC_InitStructure); USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; 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); USART_Cmd(USART1, ENABLE); /* 以上是对串口的初始化部分,USART1初始化设置:115200-8-n-1 */ /*----------------------程序主要部分---------------------------*/ for(;info[sendindex]!='\0';sendindex++)//循环发送info中的数据,直到'\0' { while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 USART_SendData(USART1, info[sendindex]); } //再发送回车换行符——0x0d、0x0a while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 USART_SendData(USART1, 0x0d); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 USART_SendData(USART1, 0x0a); //恢复发送数据索引,然后开启接收中断,等待接收数据 sendindex=0; USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); for(;;); } //usart1中断例程 void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//检查接收中断位 { buffer[recvindex]=USART_ReceiveData(USART1); recvindex++; if(buffer[recvindex-1]=='*' ||recvindex>=(BUFF_MAX-1) )//如果接收到尾字符'*'或者缓冲区buffer满 { USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//禁止接收中断 buffer[recvindex]='\0';//添加字符串结尾符 recvindex=0;//恢复接收数据索引 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//开启发送中断,准备发送数据 } } if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)//检查发送中断位 { if(buffer[sendindex]!='\0')//检查是否发送完数据,接收中断对缓冲区的处理保证了一定有'\0' { USART_SendData(USART1, buffer[sendindex]); sendindex++; } else//数据发送完成 { //发送回车换行 USART_SendData(USART1, 0x0d); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 USART_SendData(USART1, 0x0a); USART_ITConfig(USART1, USART_IT_TXE, DISABLE);//禁止发送中断 sendindex=0;//恢复发送数据索引 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能接收中断,准备接收数据 } } }

很简单的一个程序,功能是个大循环{等待输入结束,然后输出接收到的信息},虽然没有这个大循环,而是靠中断实现的。
需要注意的几个问题:

  1. 回忆上一节关于STM32中断系统的注意点
  2. 发送回车换行使用的是0x0d、0x0a,如果使用‘\n’偶尔不能正常接收。
  3. 中断例程中并没有显示的清除中断位,读写数据寄存器会清除中断位。
  4. 关于102行的循环
1.都是因为要发送0x0d、0x0a造成的,其实也可以在接收中断中接收完成时添加到buffer的结尾(此时检查条件为buffer[recvindex-1]=='*' ||recvindex>=(BUFF_MAX-3))。

2.为什么101行之前不用循环检查数据寄存器,因为如果数据寄存器为空USART_GetITStatus(USART1, USART_IT_TXE) != RESET就不会成立,而102行循环存在的必要性呢?因为要等待101行的数据发送完成,要知道虽然程序运行在中断例程之中,但是USART模块还是在独立工作的,所以会进行发送

3.在中断例程中是不应该有这种等待外设的循环的。但是中断例程甚至还以修改为下面的代码段,在中断例程中有更长时间的循环,但是整个程序依然能如期待的那样工作,因为认识到“程序运行在中断例程之中,但是USART模块还是在独立工作的,所以会进行发送”这点很重要,而且在循环之后要检查数据寄存器
//usart1中断例程 void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//检查接收中断位 { for(;buffer[recvindex-1]!='*' && recvindex<=(BUFF_MAX-1);recvindex++)//直到接收到尾子符或者缓冲区buffer满 { buffer[recvindex]=USART_ReceiveData(USART1); while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);//收到数据 } USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//禁止接收中断 buffer[recvindex]='\0';//添加字符串结尾符 recvindex=0;//恢复接收数据索引 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//开启发送中断,准备发送数据 } if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)//检查发送中断位 { for(;buffer[sendindex]!='\0';sendindex++)//直到数据发送完成 { USART_SendData(USART1, buffer[sendindex]); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 } while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 USART_SendData(USART1, 0x0d); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//USART_DR寄存器为空 USART_SendData(USART1, 0x0a); USART_ITConfig(USART1, USART_IT_TXE, DISABLE);//禁止发送中断 sendindex=0;//恢复发送数据索引 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能接收中断,准备接收数据 } }

5.对输入的结束字符只是简单的通过星号实现,实际应用中可能需要很麻烦的协议。所以输入时候要注意,没有星号而且字符数不到BUFF_MAX-1,输入是不会结束的。