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);//使能接收中断,准备接收数据
}
}
}
很简单的一个程序,功能是个大循环{等待输入结束,然后输出接收到的信息},虽然没有这个大循环,而是靠中断实现的。
需要注意的几个问题:
- 回忆上一节关于STM32中断系统的注意点
- 发送回车换行使用的是0x0d、0x0a,如果使用‘\n’偶尔不能正常接收。
- 中断例程中并没有显示的清除中断位,读写数据寄存器会清除中断位。
- 关于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,输入是不会结束的。