單片機 (MCU) 如何才能不死機之 串口(UART) Overrun

topsemic 發佈 2020-01-07T11:15:59+00:00

閒言少敘,先上Code。大家看一下下面這段代碼有沒有問題?#include "main.



閒言少敘,先上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--;

}

}

關鍵字: