网站首页 > 技术文章 正文
闲言少叙,先上Code。
大家看一下下面这段代码有没有问题?
#include "main.h"
static __IO uint32_t TimingDelay;
RCC_ClocksTypeDef RCC_Clocks;
uint8_t uart_buffer[100];
// GPIO Configuration
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1); // Tx PA9
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1); // Rx PA10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // USART1_TX | USART1_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
// USART Configuration
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
//USART_InitStructure.USART_BaudRate = 9600;
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_Tx | USART_Mode_Rx;
USART_Init(USART1,&USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1,ENABLE);
}
// Interrupt Configuration
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// USART1 interrupt Config
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
// USART1 Interrupt Handler
void USART1_IRQHandler (void)
{
static uint8_t i = 0;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!= RESET)
{// Clear Receive Data Register Not Empty Flag
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
uart_buffer[i++] = USART_ReceiveData(USART1);
if(i == 100)
i = 0;
}
}
int main(void)
{
static uint8_t ch;
// Init a 1ms timer interrupt, for Delay function implementation.
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
// Enable USART1 and GPIOA clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
GPIO_Configuration();
USART_Configuration();
NVIC_Configuration();
ch = 'A';
while(1)
{
Delay(50);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, ch);
ch++;
}
}
void Delay(__IO uint32_t nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
void TimingDelay_Decrement(void)
{
if(TimingDelay != 0x00)
{
TimingDelay--;
}
}
它是可以在 STM32F030 上调试通过的串口收发测试程序,发送采用延时循环,接收采用中断,接收到的数据存入缓冲区。
有很多比较认真的实战派的同学估计会下载到板子上跑一跑,它确实能跑通,看起来也没什么问题。很多教程甚至官方的代码都是类似的处理方法。
但这确实有点儿像陷马坑,看似一马平川,跑着跑着突然连马带人 kucha 一声掉坑里了。这还真不是开玩笑,某知名楼宇自控公司的产品就在安装到
客户现场后,经常莫名奇妙的死机。查来查去,查去查来,才发现问题。可是解决起来不容易啊,一个一个的去拆开,更新代码,想想都。。。
所以同学们不要轻视任何一段代码啊!
这段代码的问题是,如果接收数据之间间隔时间较长,可以正常收数据。但是如果对方发送数据非常快,或者偶尔在自己还没从串口接收寄存器取走数据
的时候突然又来了数据,会导致 Overrun 标志位的置位。这个标志位一置,串口基本上就罢工了。所以,在程序中一定要有对异常情况的处理。甚至觉得不会
发生的异常也不要置之不理。(想一想为什么要填充Flash的空白区域?在正常情况下代码永远不会跑到空白区域是吧。)
对串口异常的处理可以参考下面的代码。当然也可以在主程序中定时处理,以便在中断失效的情况下还能恢复。
#include "main.h"
// TopSemic
// Note: USART demo code runs on STM32F030
static __IO uint32_t TimingDelay;
RCC_ClocksTypeDef RCC_Clocks;
uint8_t uart_buffer[100];
// GPIO Configuration
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1); // Tx PA9
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1); // Rx PA10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // USART1_TX | USART1_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
// USART Configuration
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
//USART_InitStructure.USART_BaudRate = 9600;
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_Tx | USART_Mode_Rx;
USART_Init(USART1,&USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1,ENABLE);
}
// Interrupt Configuration
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// USART1 interrupt Config
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
// USART1 Interrupt Handler
void USART1_IRQHandler (void)
{
static uint8_t i = 0;
if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)
{// Clear Overrun Error Flag
USART_ClearFlag(USART1, USART_FLAG_ORE);
}
else if(USART_GetFlagStatus(USART1, USART_FLAG_NE) != RESET)
{// Clear Noise Error Flag
USART_ClearFlag(USART1, USART_FLAG_NE);
}
else if(USART_GetFlagStatus(USART1, USART_FLAG_FE) != RESET)
{// Clear Framing Error Flag
USART_ClearFlag(USART1, USART_FLAG_FE);
}
else if(USART_GetFlagStatus(USART1, USART_FLAG_PE) != RESET)
{// Clear Parity Error Flag
USART_ClearFlag(USART1, USART_FLAG_PE);
}
else if(USART_GetITStatus(USART1,USART_IT_RXNE)!= RESET)
{// Clear Receive Data Register Not Empty Flag
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
uart_buffer[i++] = USART_ReceiveData(USART1);
if(i == 100)
i = 0;
}
}
int main(void)
{
static uint8_t ch;
// Init a 1ms timer interrupt, for Delay function implementation.
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
// Enable USART1 and GPIOA clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
GPIO_Configuration();
USART_Configuration();
NVIC_Configuration();
ch = 'A';
while(1)
{
Delay(50);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, ch);
ch++;
}
}
/**
* @brief Inserts a delay time.
* @param nTime: specifies the delay time length, in 1 ms.
* @retval None
*/
void Delay(__IO uint32_t nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
/**
* @brief Decrements the TimingDelay variable.
* @param None
* @retval None
*/
void TimingDelay_Decrement(void)
{
if(TimingDelay != 0x00)
{
TimingDelay--;
}
}
猜你喜欢
- 2024-10-12 STM32单片机-多串口printf()问题与ASCII码解析
- 2024-10-12 stm32F0 串口的几个特殊功能 stm32f1串口引脚
- 2024-10-12 STM32串口发送用哪个中断? stm32f4串口发送数据
- 2024-10-12 STM32F103编程学习——USB虚拟串口篇
- 2024-10-12 STM32F4入坑日记——串口发送数据(非中断)
- 2024-10-12 STM32 HAL库串口中断发送过程 stm32f4串口中断
- 2024-10-12 在货物监控设备研发时,STM32串口第一个字节丢失解怎么解决?
- 2024-10-12 STM32单片机采用环形缓冲区实现串口中断数据接收管理
- 2024-10-12 基于STM32的串口与DMA的完美组合(上)
- 2024-10-12 STM32下载程序新思路--使用串口下载STM32程序
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)