完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、串口通讯方式 这里就不再累赘阐释了,看以前的篇章 UART/ USRAT、I2C、SPI通信方式扫盲 二、USART收发功能框图 三、USART模式配置 1、各模式功能支持 2、I/O复用配置 四、代码实现过程 在这次例程中,我们配置成 UART(异步串口),这是我们比较常用的,而 USART(同步串口)只是多了一条时钟线,所以,在用 UART时,我们需要引入一个可以判断是否接受完成的节点,可以是时间超时判定,结束符判定等等 在配置之前我们先定义一个接收的结构体 #define RxBUFFER_SIZE 0xFF typedef struct { uint8_t RxBuffer[RxBUFFER_SIZE]; // 接收暂存缓冲区 __IO uint8_t RxCounter; // 接收数据个数 uint8_t Receiving_Time; // 接收时间 uint8_t Frame_flag; // 一帧完成标志 }EVAL_COMx_TypeDef; 由于发送用的缓冲区我们可以共用(毕竟发送的时候只能单发),所以就只是定义一个数组就好了 #define TxBUFFER_SIZE 100 uint8_t g_TxCounter = 0; // 发送数据个数 uint8_t TxBuffer[TxBUFFER_SIZE] = {0}; // 发送暂存缓冲区 好了,现在就开始配置我们的 UART吧 1、UART1功能配置: #define BAUDRATE_1 115200; // 波特率设置 支持的波特率:115200,19200,9600,38400,57600,1200,2400,4800 #define EVAL_COM1 USART1 /************************************************ 函数名称 : UART1_Comfig 功 能 : UART1端口配置 参 数 : 无 返 回 值 : 无 *************************************************/ void UART1_Comfig(void) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; USART_InitTypeDef USART_InitStructure; /* config GPIOA clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* config USART1 clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /* USART1 GPIO config */ /* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Enable the USART1 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* USART1 mode config */ USART_InitStructure.USART_BaudRate = BAUDRATE_1; // 获取波特率 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(EVAL_COM1, &USART_InitStructure); USART_ITConfig(EVAL_COM1, USART_IT_RXNE, ENABLE); // 使能串口接收中断 USART_Cmd(EVAL_COM1, ENABLE); // 使能串口 } 2、中断接收处理: /************************************************************************/ /* STM32F10x USART Interrupt Handlers */ /************************************************************************/ /** * @brief This function handles USART1 global interrupt request. * @param None * @retval None */ void USART1_IRQHandler(void) { if(USART_GetITStatus(EVAL_COM1, USART_IT_RXNE) != RESET) // 判断接收 { /* Read one byte from the receive data register */ #if 0 Usart1.RxBuffer[Usart1.RxCounter++] = (USART_ReceiveData(EVAL_COM1) & 0x7F); // 如果使能了奇偶校验,则最高位 bit 8需要省掉 #else Usart1.RxBuffer[Usart1.RxCounter++] = (USART_ReceiveData(EVAL_COM1) & 0xFF); // 获取数据 #endif if(Usart1.RxCounter >= RxBUFFER_SIZE) // 判断是否超出接收最大长度 { // /* Disable the EVAL_COM1 Receive interrupt */ // USART_ITConfig(EVAL_COM1, USART_IT_RXNE, DISABLE); Usart1.Frame_flag = 0; // 接收完成标志清零 Usart1.RxCounter = 0; // 计数清零 Usart1.Receiving_Time = 0; // 接收超时时间清零 } Usart1.Receiving_Time = 2; // 设置超时判定时间 } /* 因为我们不去利用中断进行发送,所以下面的操作屏蔽掉 */ // if(USART_GetITStatus(EVAL_COM1, USART_IT_TXE) != RESET) // { // /* Write one byte to the transmit data register */ // USART_SendData(EVAL_COM1, TxBuffer[TxCounter++]); // if(TxCounter == RxBUFFER_SIZE) // { // /* Disable the EVAL_COM1 Transmit interrupt */ // USART_ITConfig(EVAL_COM1, USART_IT_TXE, DISABLE); // } // } } 在官方给的串口中断处理函数中,读取接收字符的代码为:RxBuffer[RxCount++] = (USART_ReceiveData(USART1) & 0x7F);这里为什么与的不是 0xFF而是 0x7F,这是因为在查看手册后,了解到无论串口配置时选的数据宽度为 8bit还是 9bit,其最高位一般保留为奇偶检验的结果位,因此奇偶检验使能的情况下读取实际数据的话应该省掉最高位 在这里,用了超时判定来作为是否接收完一帧,所以还要在时间定时器中进行判定,判定如下: if(Usart1.Receiving_Time) { Usart1.Receiving_Time--; if(!Usart1.Receiving_Time) Usart1.Frame_flag = 1; } 至于什么时候才算一帧数据完成,这就取决于你设定的超时时间系数 3、发送输出处理: /************************************************ 函数名称 : USART_SendByte 功 能 : 串口字符发送 参 数 : c ---- 发送的数据 返 回 值 : 无 *************************************************/ void USART_SendByte( USART_TypeDef* USARTx, uint8_t c ) { USART_SendData(USARTx, c); while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); } /************************************************ 函数名称 : USART_SendString 功 能 : 串口字符串发送 参 数 : USARTx ---- 串口 pData ---- 字符串 Length ---- 长度 返 回 值 : 无 *************************************************/ void USART_SendString( USART_TypeDef* USARTx, const uint8_t *pData, uint16_t Length ) { while(Length--) { USART_SendByte(USARTx, *pData); pData++; } } /************************************************ 函数名称 : USART_Printf 功 能 : 串口打印输出 参 数 : USARTx ---- 串口 String ---- 字符串 返 回 值 : 无 *************************************************/ void USART_Printf( USART_TypeDef* USARTx, char *String ) { do { USART_SendByte(USARTx, *String); String++; }while((*String) != ' |