STM32F103RCT6芯片的正点原子mini开发板学习笔记(6)
本节针对串口通信UART进行说明。首先对基础知识进行说明1.通信分为并行通信串行通信。单工半双工全双工。同步异步。串口通讯Serial Communication是一种设备间非常常用的串行通讯方式因为它简单便捷因此大部分电子设备都支持该通讯方式电子工程师在调试设备时也经常使用该 通讯方式输出调试信息。32单片机Tx发电脑或其他设备Rx接收。其他设备Tx发32单片机Rx收。通信协议如图波特率表示每秒传输了多少个码元。比特率表示每秒传输了多少个bit。常见波特率48009600115200空闲位串口协议规定当总线处于空闲状态时信号线的状态为‘1’即高电平表示当前线路上 没有数据。USART是通用同步异步收发器是一个串行通信设备可以灵活地与外部设备进行全双工数据交换。UART相比USART去掉了同步通讯功能。在正点原子mini开发板中PA9PA10分别对应USART1_TX和USART1_RX。想要实现串口通信一般有两种方式一种是通过while循环的方式一直查看有没有接收或者需要发送消息。这样的做法非常浪费系统资源且容易使系统阻塞卡死在循环内。第二种方式是通过中断的方式在产生USART中断事件时接收或者发送数据。以下是配置代码首先是对时钟的配置串口外设时钟的开启在APB2总线上开启USART1,再开启GPIOA的时钟并配置PA9 PA10,PA9对应发送端口所以需要配置为复用推挽输出模式PA10是接收口需要配置为浮空输入模式。其次我们需要对串口参数进行配置1.设置波特率115200。2.配置一个字的长度为8位。3.配置不需要校验位。4.配置停止位长度。5.使能接收和发送。中间三个都是默认配置好的也可以不写。最后配置中断设置优先级组设置优先级开启中断使能使能串口。中断标志位清除有时候需要通过/* 清除空闲中断标志位: 先读sr,再读dr.就可以实现清除了 */USART1-SR;USART1-DR;#include Driver_USART.h /** * description: 初始化串口1 */ void Driver_USART1_Init(void) { /* 1. 开启时钟 */ /* 1.1 串口1外设的时钟 */ RCC-APB2ENR | RCC_APB2ENR_USART1EN; /* 1.2 GPIO时钟 */ RCC-APB2ENR | RCC_APB2ENR_IOPAEN; /* 2. 配置GPIO引脚的工作模式 PA9Tx(复用推挽 CNF10 MODE11) PA10Rx(浮空输入 CNF01 MODE00)*/ GPIOA-CRH | GPIO_CRH_CNF9_1; GPIOA-CRH ~GPIO_CRH_CNF9_0; GPIOA-CRH | GPIO_CRH_MODE9; GPIOA-CRH ~GPIO_CRH_CNF10_1; GPIOA-CRH | GPIO_CRH_CNF10_0; GPIOA-CRH ~GPIO_CRH_MODE10; /* 3. 串口的参数配置 */ /* 3.1 配置波特率 115200 */ USART1-BRR 0x271; /* 3.2 配置一个字的长度 8位 */ USART1-CR1 ~USART_CR1_M; /* 3.3 配置不需要校验位 */ USART1-CR1 ~USART_CR1_PCE; /* 3.4 配置停止位的长度 */ USART1-CR2 ~USART_CR2_STOP; /* 3.5 使能接收和发送 */ USART1-CR1 | USART_CR1_TE; USART1-CR1 | USART_CR1_RE; /* 3.6 使能串口的各种中断 */ USART1-CR1 | USART_CR1_RXNEIE; /* 接收非空中断 */ USART1-CR1 | USART_CR1_IDLEIE; /* 空闲中断 */ /* 4. 配置NVIC */ /* 4.1 配置优先级组 */ NVIC_SetPriorityGrouping(3); /* 4.2 设置优先级 */ NVIC_SetPriority(USART1_IRQn, 2); /* 4.3 使能串口1的中断 */ NVIC_EnableIRQ(USART1_IRQn); /* 4. 使能串口 */ USART1-CR1 | USART_CR1_UE; } /** * description: 发送一个字节 * param {uint8_t} byte 要发送的字节 */ void Driver_USART1_SendChar(uint8_t byte) { /* 1. 等待发送寄存器为空 */ while ((USART1-SR USART_SR_TXE) 0) ; /* 2. 数据写出到数据寄存器 */ USART1-DR byte; } /** * description: 发送一个字符串 * param {uint8_t} *str 要发送的字符串 * param {uint16_t} len 字符串中字节的长度 * return {*} */ void Driver_USART1_SendString(uint8_t *str, uint16_t len) { for (uint16_t i 0; i len; i) { Driver_USART1_SendChar(str[i]); } } /** * description: 接收一个字节的数据 * return {*} 接收到的字节 */ uint8_t Driver_USART1_ReceiveChar(void) { /* 等待数据寄存器非空 */ while ((USART1-SR USART_SR_RXNE) 0) ; return USART1-DR; } /** * description: 接收变长数据.接收到的数据存入到buff中 * param {uint8_t} buff 存放接收到的数据 * param {uint8_t} *len 存放收到的数据的字节的长度 */ void Driver_USART1_ReceiveString(uint8_t buff[], uint8_t *len) { uint8_t i 0; while (1) { // 等待接收非空 while ((USART1-SR USART_SR_RXNE) 0) { // 在等待期间, 判断是否收到空闲帧 if (USART1-SR USART_SR_IDLE) { *len i; return; } } buff[i] USART1-DR; i; } } /* 缓冲接收到的数据 */ uint8_t buff[100] {0}; /* 存储接收到的字节的长度 */ uint8_t len 0; uint8_t isToSend 0; void USART1_IRQHandler(void) { /* 数据接收寄存器非空 */ if (USART1-SR USART_SR_RXNE) { // 对USART_DR的读操作可以将接收非空的中断位清零。 所以不用单独清除了. //USART1-SR ~USART_SR_RXNE; buff[len] USART1-DR; len; } else if (USART1-SR USART_SR_IDLE) { /* 清除空闲中断标志位: 先读sr,再读dr.就可以实现清除了 */ USART1-SR; USART1-DR; /* 变长数据接收完毕 */ //Driver_USART1_SendString(buff, len); isToSend 1; /* 把接收字节的长度清0 */ // len 0; } }以下是主程序代码/* 缓冲接收到的数据 */ extern uint8_t buff[100]; /* 存储接收到的字节的长度 */ extern uint8_t len; extern uint8_t isToSend; int main() { Driver_USART1_Init(); Driver_USART1_SendString(abc, 3); while (1) { if(isToSend){ Driver_USART1_SendString(buff, len); isToSend 0; len 0; } } }