一、简介
在上一次我们学习了如何使用查询的方式进行串口通讯——发送数据,以及中断的方式,在本次我们使用中断来进行串口通讯。
可以参考以前的博客:
串口通讯:STM32串口通讯实现——USB转串口.
中断:STM32使用中断方式读取按键控制LED灯的亮灭.
二、代码编写
代码部分我是在别人博客进行复制的:链接: 基于 stm32 的应用实例 —— USART 串口通讯(stm32 与主机通讯).
需要输入的内容在bsp_usart.c当中进行修改即可,其它的文件都是库,不需要更改
1.代码分析
bsp_usart.c文件程序:
#include "bsp_usart.h"
// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucTemp;
//串口一接收中断
if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
{
//获取接收到的数据
ucTemp = USART_ReceiveData(DEBUG_USARTx);
//如果接收标志为 0 ,则执行下面的部分
if((USART_RX_FLAG & 0x8000) == 0)
{
//接收到了0x0d
if(USART_RX_FLAG & 0x4000)
{
//接收错误,重新开始
if(ucTemp != 0x0a)
USART_RX_FLAG=0;
//接收完成
else
USART_RX_FLAG |= 0x8000;
}
//还未接收到0x0d
else
{
//接收到回车
if(ucTemp == 0x0d)
{
USART_RX_FLAG |= 0x4000;
}
else
{
USART_RX_BUF[USART_RX_FLAG & 0x3FFF] = ucTemp;
USART_RX_FLAG++;
//接收数据错误,重新开始接收
if(USART_RX_FLAG > 99)
USART_RX_FLAG = 0;
}
}
}
}
}
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打开串口GPIO的时钟
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
// 将USART Tx的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
// 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
// 配置针数据字长
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(DEBUG_USARTx, &USART_InitStructure);
// 串口中断优先级配置
NVIC_Configuration();
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
// 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);
}
/* 发送一个字节 */
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
//发送数据函数(串口一,数据)
USART_SendData(pUSARTx, data);
//发送数据寄存器为空,则退出
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/* 发送字符串 */
void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str)
{
uint8_t i = 0;
do
{
Usart_SendByte(pUSARTx, *(str+i));
i++;
}while(*(str+i) != '\0');
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}
//微秒级的延时
void delay_us(uint32_t delay_s)
{
volatile unsigned int i;
volatile unsigned int t;
for (i = 0; i < delay_s; i++)
{
t = 11;
while (t != 0)
{
t--;
}
}
}
//毫秒级的延时函数
void delay_ms(uint16_t delay_ms)
{
volatile unsigned int num;
for (num = 0; num < delay_ms; num++)
{
delay_us(1000);
}
}
//连续发送数据
void Usart_SendString(void)
{
uint8_t i = 0;
while(1)
{
if(USART_RX_FLAG & 0x8000)
{
// 获取接收到的数据长度
len = USART_RX_FLAG & 0x3FFF;
Usart_SendStr(DEBUG_USARTx, "\n");
for(i=0; i<len;i++)
{
// 向串口发送数据
USART_SendData(DEBUG_USARTx, USART_RX_BUF[i]);
//等待发送结束
while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TC)!=SET);
}
Usart_SendStr(DEBUG_USARTx, "\n\n");
//比较字符串
if(strcmp((char *)USART_RX_BUF,"stop,stm32!")==0)
{
Usart_SendStr(DEBUG_USARTx, "stm32已停止发送!");
break;//退出循环
}
//初始化
USART_RX_FLAG=0;
memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));
}
else
{
//循环发送数据
Usart_SendStr(DEBUG_USARTx, "梓宝带我走吧\n");
delay_ms(800);
}
}
}
在程序当中定义了一个串口中断服务函数用于控制中断,以及NVIC的嵌套向量中断控制器函数。
2.程序烧录
接线之后,打开mcuisp软件,将生成的.hex文件烧录到芯片当中
三、实验效果
在输入框当中输入stop,stm32!
然后换行,发送,就可以看到数据发送停止了
四、总结
通过此次实验,使用中断的方式进行串口通讯后,以及学习了三种串口通讯方式了:查询,中断和DMA。在实际的通讯过程当中,我们可以根据需求进行选择,在传输比较大的数据的时候采用DMA方式,可以解放CPU,让CPU进行别的工作。中断方式是通过中断服务函数不断将数据放到串口进行传送。每一种方式都有优缺点,我们学习完这些方法后要学会在不同场景下进行使用。
参考资料: 基于 stm32 的应用实例 —— USART 串口通讯(stm32 与主机通讯)