1 串口通信协议
串口通信协议可分为物理层与协议层。
物理层是硬件部分,规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。
协议层是软件部分,主要规定通讯逻辑,统一收发双方的数据打包、解包标准。
串口数据包的基本组成:
-
起始位:由1个逻辑0的数据位表示。
-
结束位:由 0.5 、1、 1.5 或2个逻辑1的数据位表示。
-
有效数据:在起始位后紧接着的就是有效数据,有效数据的长度常被约定为5、6、7、或8位。
-
校验位:检测数据是否出错。
下方链接为 关于UART与USART通信串口数据包的基本组成 更详细的介绍。
UART与USART介绍
2 STM32串口功能框图
串口功能框图: STM32F10X - 参考手册 图248
2.1 功能引脚
-
TX:发送数据输出引脚。
-
RX:接收数据输入引脚。
-
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
-
nRTS:请求以发送 (Request To Send), n 表示低电平有效。
如果使能 RTS 流控制,当 USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时, nRTS 将被设置为高电平。该引脚只适用于硬件流控制。
- nCTS:清除以发送 (Clear To Send), n 表示低电平有效。
如果使能 CTS 流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
- SW_RX:Software UART(软件串行通信)接收引脚。
用于通过软件实现的UART(通用异步收发器)通信,通常用于调试和与其他串行设备通信。
-
IRDA_OUT:红外数据传输的输出引脚。用于红外数据传输,通常用于遥控器、红外数据通信等应用。
-
IRDA_IN:外数据传输的输入引脚。它用于接收红外数据,例如从遥控器或其他红外发射设备接收数据。
上图为 STM32F103ZET6芯片的USART引脚 。
还有一些引脚为复用引脚,在 STM32F10X - 参考手册 8.3.8 USART复用功能重映射 查看。
为什么UART没有SCLK、nRTS、nCTS:s表示synchronous(同步),UART为异步,不需要这三个引脚。
2.2 数据寄存器
数据寄存器——USART_DR:9位有效,包含一个发送数据寄存器TDR和一个接收数据寄存器RDR。一个地址对应两个物理内存。
2.3 控制器
USART的控制寄存器有三个:USART_CR1、USART_CR2、USART_CR3,其中USART_CR3主要与硬件控制流相关。
在 章节1串口通信协议 中我们了解了串口数据包的基本组成有起始位、数据位、校验位和停止位。
-
数据位的长度由USART_CR1寄存器的位12(M)控制:当M为0时数据位为8为;当M为1时数据位为9位。
-
停止位的长度由USART_CR2寄存器的位12、13(STOP)控制。
-
校验位由USART_CR1寄存器的位10(PCE:校验控制使能)与位9(PS:校验选择)控制。
与中断相关的寄存器位:PEIE、UE、TE、RE、TXE、TXEIE、TC、TCIE、RXNE、RXNEIE。
-
PEIE:PE中断使能,USART_CR1位8。
- 0表示禁止产生中断。
- 1表示当USART_SR中的PE为1时,产生USART中断。
-
UE:USART使能,USART_CR1位13。
- 0表示USART分频器和输出被禁止。
- 1表示USART模块使能。
-
TE:发送使能,USART_CR1位3。
- 0表示禁止发送。
- 1表示使能发送。
-
RE:接收使能,USART_CR1位2。
- 0表示禁止接收。
- 1表示使能接收,并开始搜寻RX引脚上的起始位。
-
TXE:发送数据寄存器空,USART_SR位7。
- 0表示数据还没有被转移到移位寄存器。
- 1表示数据已经被转移到移位寄存器。
-
TXEIE:发送缓冲区空中断使能,USART_CR1位7。
- 0表示禁止产生中断。
- 1表示当USART_SR中的TC为’1’时,产生USART中断。
-
TC:发送完成 ,USART_SR位6。
- 0表示发送还未完成。
- 1表示发送完成。
-
TCIE:发送完成中断使能,USART_CR1位6。
- 0表示禁止产生中断。
- 1表示当USART_SR中的TC为’1’时,产生USART中断。
-
RXNE:读数据寄存器非空,USART_SR位5。
- 0表示数据没有收到。
- 1表示收到数据,可以读出。
-
RXNEIE:接收缓冲区非空中断使能 ,USART_CR1位5。
- 0表示禁止产生中断。
- 1表示当USART_SR中的ORE或者RXNE为’1’时,产生USART中断。
2.3.1 USART_CR1
2.3.2 USART_CR2
2.3.3 USART_CR3
2.3.4 USART_SR
2.4 数据发送与接收的具体流程
2.4.1 数据发送
发送数据时:UE = 1, TE = 1。
要发送的数据来自CPU或DMA,从内存中读取;有了数据之后将数据放到发送数据寄存器(TDR),发送TDR的数据时会将数据(8位)放到发送移位寄存器,再由发送移位寄存器一位一位的发送出去,发送到TX引脚。
在这个过程中,有两个寄存器的状态位发送了改变:
-
1.发送数据寄存器中的数据发送到发送移位寄存器时,TXE(Transmit Empty)为1表示发送数据寄存器为空,但并不表示数据已经发送出去。
-
2.发送移位寄存器中的数据发送完成了,TC(Transmit Complete)为1表示数据已经发送出去了。
2.4.2 数据接收
接收数据时:UE = 1,RE = 1。
接收数据从RX引脚中来,数据接收的时候是一位一位的接收;首先将接收到的数据放到接收移位寄存器中,然后再把数据传送到接收数据寄存器(RDR),这时RXNE(Receive Not Empty)会置1表示接收数据寄存器不是空的,这时数据可以读出。
2.5 比特率
设置串口通信比特率的寄存器为USART_BRR。
比特率的计算公式如下:
-
fCK:串口的时钟,注意区分APB2(36M)和APB1(72M)两条总线。
-
USARTDIV:无符号的定点数。
我们想要使用APB1总线时钟来设置比特率为115200的串口,那么它的USARTDIV该怎么配置呢?
- 小数部分为什么要乘16:小数部分有4位,可表示0 ~ 15(0000 ~ 1111),小数部分的最大值不能超过1.0000,因此最小精度为1/16,算出的0.0625除以(1/16)就是DIV_Fraction的值。
3 代码讲解
3.1 硬件设计
上图为 野火_指南者原理图中的USB转串口模块电路图。
我们将指南者上的PA10、PA9与USART1_RX、USART1_TX用跳线帽连接。注意板子上的RX与CH340G的TX相连,TX与CH340G的RX相连。
3.2 软件设计
为了使工程更加有条理,我们把USART相关的代码独立分开存储,方便以后移植。在“工程模板”上新建 usart.c文件 与 usart.h 文件。
在本次学习中,我们需要实现以下功能:
-
功能1.单片机给电脑发送数据,电脑上位机把数据打印处理。
-
功能2.电脑上位机给单片机发数据,单片机接收到数据后立马发回给电脑,并打印处理。
-
功能3.电脑给单片机发送命令,用于控制开发板上的RGB灯。
3.2.1 编程要点:
-
1.初始化串口需要用到的GPIO:时钟(GPIO)、GPIO口的模式。
-
2.初始化串口,USART_InitTypeDef:先打开时钟(USART),再配置串口的工作参数。
-
3.中断配置:接收中断,中断优先级。
-
4.使能串口。
-
5.编写发送和接收函数。
-
6.编写中断服务函数。
// usart.h 文件
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
/**
* 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
* 2-修改GPIO的宏
*/
// 串口1-USART1
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
void USART_Config(void);
#endif /* __USART_H */
// usart.c 文件
#include "usart.h"
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
/* 提示 NVIC_PriorityGroupConfig() 在整个工程只需要调用一次来配置优先级分组 */
/* 这时只有串口接收的中断,组可以随便分。抢占优先级与子优先级也可以随便配置。 */
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);
}
/**
* @brief USART GPIO 配置,工作参数配置
* @param 无
* @retval 无
*/
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 1.1 打开串口GPIO的时钟
RCC_APB2PeriphClockCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 2.1 打开串口外设的时钟
RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
// 1.2 将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);
// 1.3 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
/* RX引脚为什么要选择浮空输入:外部发送什么数据到引脚,引脚就体现出什么电平 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
// 2.2 配置串口的工作参数
/* 上位机串口调试助手的参数要与软件设置的参数一致。 */
// 配置波特率
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);
// 3.1 串口中断优先级配置
NVIC_Configuration();
// 3.2 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
// 4 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);
}
3.2.2 串口发送数据
3.2.2.1 发送一个字节
// usart.c 文件
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
USART_SendData(pUSARTx, data); // 这个函数可以在 stm32f10x.h 文件中找到
// 等待发送数据寄存器为空
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) != SET);
// while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC != SET); 这样写也可以
}
// usart.h 文件
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data);
// main.c 文件
#include "stm32f10x.h"
#include "usart.h"
int main(void)
{
USART_Config();
Usart_SendByte(DEBUG_USARTx, 0xff);
while(1)
{
}
}
将编译后的代码烧录到板子中,可以在上位机串口助手看到单片机发送的数据。
点击波特率上方的更多串口设置,出现下面的以下设置,这些设置要与 USART_Config() 函数中设置的参数一致。
3.2.2.2 发送两个字节
// usart.c 文件
/* 发送两个字节,需要在 usart.h 文件中声明 */
void Usart_SendTwoByte(USART_TypeDef* pUSARTx, uint16_t data)
{
uint8_t temp_h, temp_l;
temp_h = (data&0xFF00) >> 8;
temp_l = data&0xFF;
Usart_SendByte(pUSARTx, temp_h);
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) != SET);
Usart_SendByte(pUSARTx, temp_l);
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) != SET);
}
发送一个字节判断USART_FLAG_TXE,发送一连串数据判断用USART_FLAG_TC。
3.2.2.3 发送8位数据的数组
// usart.c 文件
/* 发送8位数组,需要在 usart.h 文件中声明*/
void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array, uint8_t num)
{
uint8_t i;
for(i = 0; i<num; i++)
{
Usart_SendByte(pUSARTx, array[i]);
// USART_SendData(pUSARTx, array[i]); 只会发送最后一个数据
}
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) != SET);
}
- 如果将 Usart_SendByte(pUSARTx, array[i]) 更换为 USART_SendData(pUSARTx, array[i]) ,我们在串口助手上只能看到数组array的最后一个数据:前面的数据还没等发送完成,后面的数据就存入到发送数据寄存器中,覆盖掉了前面的数据。
3.2.2.4 发送一个字符串
// usart.c 文件
/* 发送一个字符串,需要在 usart.h 文件中声明 */
void Usart_SendString(USART_TypeDef* pUSARTx, uint8_t *str)
{
uint8_t i = 0;
while(*(str+i) != '\0')
{
Usart_SendByte(pUSARTx, *(str+i));
i++;
}
while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) != SET);
}
3.2.2.5 重定向函数
// usart.c 文件
// 重定向C库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) != SET);
return (ch);
}
// 重定向C库函数scanf到串口,重定向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) != SET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
3.2.2.6 函数实现结果
int main(void)
{
uint8_t array[3] = {0xff, 0x12, 0x11};
USART_Config();
Usart_SendByte(DEBUG_USARTx, 0xff);
Usart_SendTwoByte(DEBUG_USARTx, 0x1234);
Usart_SendArray(DEBUG_USARTx, array, 3);
Usart_SendString(DEBUG_USARTx, "每天坚持学习!\n");
printf("每天坚持学习!\n");
while(1)
{
}
}
-
在查看串口助手时,如果勾上HEX显示(十六进制显示),那么就看不到中文字符(如上图所示)。
-
在查看串口助手时,如果不勾上HEX显示,那么数据就会以ASCII码的形式显示,没有对应能够显示ASCII的数据就不能在串口助手上看到
3.2.3 串口2345代码移植
// usart.h 文件
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include <stdio.h>
/**
* 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
* 2-修改GPIO的宏
*/
/* 要使用哪个串口,将对应的串口置1,其他的清零 */
#define DEBUG_USART1 0
#define DEBUG_USART2 1
#define DEBUG_USART3 0
#define DEBUG_USART4 0
#define DEBUG_USART5 0
#if DEBUG_USART1
// 串口1-USART1
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
#elif DEBUG_USART2
//串口2-USART2
#define DEBUG_USARTx USART2
#define DEBUG_USART_CLK RCC_APB1Periph_USART2
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
#define DEBUG_USART_IRQ USART2_IRQn
#define DEBUG_USART_IRQHandler USART2_IRQHandler
#elif DEBUG_USART3
//串口3-USART3
#define DEBUG_USARTx USART3
#define DEBUG_USART_CLK RCC_APB1Periph_USART3
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOB
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_RX_GPIO_PORT GPIOB
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
#define DEBUG_USART_IRQ USART3_IRQn
#define DEBUG_USART_IRQHandler USART3_IRQHandler
#elif DEBUG_USART4
//串口4-UART4
#define DEBUG_USARTx UART4
#define DEBUG_USART_CLK RCC_APB1Periph_UART4
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOC
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_RX_GPIO_PORT GPIOC
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
#define DEBUG_USART_IRQ UART4_IRQn
#define DEBUG_USART_IRQHandler UART4_IRQHandler
#elif DEBUG_USART5
//串口5-UART5
#define DEBUG_USARTx UART5
#define DEBUG_USART_CLK RCC_APB1Periph_UART5
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOC
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
#define DEBUG_USART_RX_GPIO_PORT GPIOD
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
#define DEBUG_USART_IRQ UART5_IRQn
#define DEBUG_USART_IRQHandler UART5_IRQHandler
#endif
void USART_Config(void);
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data);
void Usart_SendTwoByte(USART_TypeDef* pUSARTx, uint16_t data);
void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array, uint8_t num);
void Usart_SendString(USART_TypeDef* pUSARTx, uint8_t *str);
#endif /* __USART_H */
-
使用其他串口发送数据,将RXD、TXD与PA9、PA10的跳帽线拿掉,用杜邦线将要使用的串口与RXD、TXD相连。(RXD与TX连,TXD与RX连)
-
更改了串口(如串口1改为串口2),但在串口助手上只能看到数据0x00。
-
原因:在串口初始化函数 USART_Config() 中,没有将相对应的外设时钟打开。
-
解决方法:在串口初始化函数 USART_Config() 中,开启外设时钟 RCC_APB1PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
-
-
为什么会发送无效数据?
-
原因:这是由于STATUS寄存器的上电初始值有问题,Usart的发送数据寄存器有一个缓冲移位寄存器,并且发送有两个状态,一个是发送数据寄存器为空,一个是移位寄存器发送完成。上电后Usart的状态寄存器的发送完成位为0,造成了上电以后会始终会有一个值被发送,这个值就是发送移位寄存器中的值,而这个值有时候是0X00有时候是0XFE 。
-
解决方法:在初始化的时候先初始化Usart,然后再配置Usart的GPIO位。
-
3.2.4 串口接收函数
为了方便中断管理,我们将串口中断服务函数放在 stm32f10x_it.c 文件中。
// stm32f10x_it.c 文件
// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{
uint8_t Temp;
if(USART_GetFlagStatus(DEBUG_USARTx, USART_IT_RXNE) != RESET)
{
Temp = USART_ReceiveData(DEBUG_USARTx);
USART_SendData(DEBUG_USARTx, Temp);
}
}
3.2.5 串口发送命令控制RGB灯
3.2.5.1 中断
通过使用中断接收数据,可以在主函数中对接收到的数据进行处理,也可以直接在中断中对接收到的数据进行处理。
以下为 “在主函数中对接收到的数据进行处理” 的部分代码。
// stm32f10x_it.c 文件
#include "usart.h"
uint8_t Temp = 0;
// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{
if(USART_GetFlagStatus(DEBUG_USARTx, USART_IT_RXNE) != RESET)
{
Temp = USART_ReceiveData(DEBUG_USARTx);
USART_SendData(DEBUG_USARTx, Temp);
}
}
// main.c
#include "stm32f10x.h"
#include "bsp_led.h"
#include "usart.h"
extern uint8_t Temp;
int main(void)
{
USART_Config();
LED_G_GPIO_Config();
LED_B_GPIO_Config();
LED_R_GPIO_Config();
while(1)
{
switch(Temp)
{
case 0x12:
LED_B(1);
break;
case 0x34:
LED_R(1);
break;
case 0x56:
LED_G(1);
break;
default:
LED_B(0);
LED_R(0);
LED_G(0);
break;
}
}
}
以下为在 “中断中对接收到的数据进行处理” 的部分代码。
// stm32f10x_it.c 文件
#include "usart.h"
#include "bsp_led.h"
// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{
uint8_t Temp ;
if(USART_GetFlagStatus(DEBUG_USARTx, USART_IT_RXNE) != RESET)
{
Temp = USART_ReceiveData(DEBUG_USARTx);
USART_SendData(DEBUG_USARTx, Temp);
switch(Temp)
{
case 0x12:
LED_B(1);
break;
case 0x34:
LED_R(1);
break;
case 0x56:
LED_G(1);
break;
default:
LED_B(0);
LED_R(0);
LED_G(0);
break;
}
}
}
// main.c
#include "stm32f10x.h"
#include "bsp_led.h"
#include "usart.h"
int main(void)
{
USART_Config();
LED_G_GPIO_Config();
LED_B_GPIO_Config();
LED_R_GPIO_Config();
while(1)
{
}
}
3.2.5.2 查询
使用查询的方法需要将中断相关的代码都注释掉。
#include "stm32f10x.h"
#include "bsp_led.h"
#include "usart.h"
int main(void)
{
uint8_t ch;
USART_Config();
LED_G_GPIO_Config();
LED_B_GPIO_Config();
LED_R_GPIO_Config();
while(1)
{
ch = getchar();
switch(ch)
{
case 0x12:
LED_B(1);
break;
case 0x34:
LED_R(1);
break;
case 0x56:
LED_G(1);
break;
default:
LED_B(0);
LED_R(0);
LED_G(0);
break;
}
}
}