第三课--EFM32GG11系列--串口接收不定长度数据的几种方式
一、硬件串口引腳定義
PE10-->USART0-TX
PE11-->USART0-RX
上面表格中,紅色方框畫出的內容用程序實現如下,在串口初始化時需要實現,不過經本人測試過,把這段代碼屏蔽掉串口仍然可正常使用,有點不理解,望大佬可以幫忙解答,不勝感激。
usart->ROUTELOC0 = (usart->ROUTELOC0& ~(_USART_ROUTELOC0_TXLOC_MASK| _USART_ROUTELOC0_RXLOC_MASK))//串口收發引腳映射
? ? ? ? ? ? ? ? ? ?|(_USART_ROUTELOC0_TXLOC_LOC0 << _USART_ROUTELOC0_TXLOC_SHIFT)
? ? ? ? ? ? ? ? ? ?|(_USART_ROUTELOC0_RXLOC_LOC0 << _USART_ROUTELOC0_RXLOC_SHIFT);
二、串口程序實現
方式1:串口+定時器
用定時器作為串口接收不定數據長度的接收超時機制實現串口收發功能,程序如下所示:
#include <stdint.h>
#include <string.h>
#include "em_device.h"
#include "em_chip.h"
#include "em_emu.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_usart.h"
#include "bsp.h"
#include "em_timer.h"
/* Declare a circular buffer structure to use for Rx and Tx queues */
#define BUFFERSIZE ? ? ? ? ?256
struct UASRT0Buffer
{
? uint8_t ?data[BUFFERSIZE]; //數據接收Buff
?? ?uint8_t ?delayMs;//接收延時時長變量
?? ?bool ? ? receivingFlg;//接收標志
?? ?bool ? ? received;//接收完成標志
? uint16_t rxByteCnt; //接收數據長度
} usart0RxBuf;
uint32_t getCoreClock = 0;
USART_TypeDef ? ? * usart;
volatile uint32_t msTicks; /* counts 1ms timeTicks */
/***************************************************************************//**
?* SysTick_Handler
?*系統嘀嗒定時器中斷服務函數
?******************************************************************************/
void SysTick_Handler(void)
{
? msTicks++; ? ? ? /* increment counter necessary in Delay()*/
}
/***************************************************************************//**
?* @brief Delays number of msTick Systicks (typically 1 ms)
?* @param dlyTicks Number of ticks to delay
?******************************************************************************/
void Delay(uint32_t dlyTicks)
{
? uint32_t curTicks;
? curTicks = msTicks;
? while ((msTicks - curTicks) < dlyTicks) ;
}
/***************************************************************************//**
?* SysTick_Init
?*系統嘀嗒定時器中斷初始化
?******************************************************************************/
void SysTickInit(void)
{
?? ? getCoreClock = CMU_ClockFreqGet(cmuClock_CORE);
? ?/*設置系統嘀嗒定時器為1s*/
? ?if (SysTick_Config( getCoreClock / 1000))?
? ?{
? ? ? while (1) ;
? ?}
}
/******************************************************************************
* @brief ?UsartInit function
*串口0初始化
******************************************************************************/
void Usart0Init(void)
{
?? ?/* Enable clock for GPIO module (required for pin configuration) */
? CMU_ClockEnable(cmuClock_GPIO, true);
?? ?
? /* Enable clock for USART module */
? CMU_ClockEnable(cmuClock_USART0, true);
?? ?
? /* Configure GPIO pins */
? GPIO_PinModeSet(gpioPortE, 10, gpioModePushPull, 1);//串口0發送引腳配置為推挽輸出
? GPIO_PinModeSet(gpioPortE, 11, gpioModeInput, 1);//串口0接收引腳配置為輸入
? /* Setup USART0 in async mode */
?? ?usart ? = USART0;
?? ?USART_InitAsync_TypeDef uartInit = USART_INITASYNC_DEFAULT;
?? ?
? /* Prepare struct for initializing UART in asynchronous mode*/
? uartInit.enable ? ? ? = usartDisable; ? /* Don't enable UART upon intialization */
? uartInit.refFreq ? ? ?= 0; ? ? ? ? ? ? ?/* Provide information on reference frequency. When set to 0, the reference frequency is */
? uartInit.baudrate ? ? = 115200; ? ? ? ? /* Baud rate */
? uartInit.oversampling = usartOVS16; ? ? /* Oversampling. Range is 4x, 6x, 8x or 16x */
? uartInit.databits ? ? = usartDatabits8; /* Number of data bits. Range is 4 to 10 */
? uartInit.parity ? ? ? = usartNoParity; ?/* Parity mode */
? uartInit.stopbits ? ? = usartStopbits1; /* Number of stop bits. Range is 0 to 2 */
? uartInit.mvdis ? ? ? ?= false; ? ? ? ? ?/* Disable majority voting */
? uartInit.prsRxEnable ?= false; ? ? ? ? ?/* Enable USART Rx via Peripheral Reflex System */
? uartInit.prsRxCh ? ? ?= usartPrsRxCh0; ?/* Select PRS channel if enabled */
? /* Initialize USART with uartInit struct */
? USART_InitAsync(usart, &uartInit);
? /* Prepare UART Rx and Tx interrupts */
? USART_IntClear(usart, _UART_IF_MASK);
? USART_IntEnable(usart, UART_IF_RXDATAV);
? NVIC_ClearPendingIRQ(USART0_RX_IRQn);
? NVIC_ClearPendingIRQ(USART0_TX_IRQn);
? NVIC_EnableIRQ(USART0_RX_IRQn);
? NVIC_EnableIRQ(USART0_TX_IRQn);
? /* Enable I/O pins at USART0 location #0 */
? usart->ROUTEPEN = (1<<1)|(1<<0);//IO復用串口功能收發使能
?? ?
?? ?usart->ROUTELOC0 = (usart->ROUTELOC0& ~(_USART_ROUTELOC0_TXLOC_MASK| _USART_ROUTELOC0_RXLOC_MASK))//串口收發引腳映射
? ? ? ? ? ? ? ? ? ?|(_USART_ROUTELOC0_TXLOC_LOC0 << _USART_ROUTELOC0_TXLOC_SHIFT)
? ? ? ? ? ? ? ? ? ?|(_USART_ROUTELOC0_RXLOC_LOC0 << _USART_ROUTELOC0_RXLOC_SHIFT);
?? ?/* Enable UART */
? USART_Enable(usart, usartEnable);
}
/******************************************************************************
?* @brief ?uartPutData function
?*
?*****************************************************************************/
void UsartPutData(USART_TypeDef *usart,uint8_t * dataPtr, uint16_t dataLen)
{
?? ?while(dataLen--)//根據需要發送的數據長度判定要發出去多少個字節
?? ?{
?? ??? ??? ?while (!(usart->STATUS & USART_STATUS_TXBL));?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ?USART0->TXDATA = (uint32_t)(*(dataPtr++));
?? ??? ?}
}
/***************************************************************************//**
*Timer0Init
*定時器0初始化
?******************************************************************************/
void Timer0Init(void)
{
?? ?/* Enable clock for TIMER0 module */
? CMU_ClockEnable(cmuClock_TIMER0, true);
? ?/* Select TIMER0 parameters */ ?
? TIMER_Init_TypeDef timerInit =
? {
? ? .enable ? ? = true, /* 初始化結束不使能 */
? ? .debugRun ? = true, /* 調試 Halt 時停止計數 */
? ? .prescale ? = timerPrescale16, /* 16 分頻 */
? ? .clkSel ? ? = timerClkSelHFPerClk, /* 時鐘源選擇高頻外設時鐘 */
? ? .fallAction = timerInputActionNone, /* 配置下降沿行為 */
? ? .riseAction = timerInputActionNone, /* 配置上升沿行為 */
? ? .mode ? ? ? = timerModeUp, /* 配置計數模式 */
? ? .dmaClrAct ?= false, /* 當使用 DMA 功能時,該配置若置位則允許在 DMA 請求信號發出后自動清除請求信號 */
? ? .quadModeX4 = false, /* 在正交編碼中是否使用 X4 模式 */
? ? .oneShot ? ?= false, /* 是否使用單次模式 */
? ? .sync ? ? ? = false, /* 定時器由其它定時器控制 */
? };
??
? /* Enable overflow interrupt */
? TIMER_IntEnable(TIMER0, TIMER_IF_OF);/* 使能 TIMER1 溢出中斷 */
??
? /* Enable TIMER0 interrupt vector in NVIC */
? NVIC_EnableIRQ(TIMER0_IRQn);/* 使能 TIMER0 中斷 */
??
? /* Set TIMER Top value */
? TIMER_TopSet(TIMER0,62500);//外部晶振為50MHz,定時器設置時選擇16分頻,定時器的時鐘頻率為50M/16=3.125MHz,62500*(1/3.125MHz)=20ms
??
? /* Configure TIMER */
? TIMER_Init(TIMER0, &timerInit);/* 初始化 TIMER0 計數器 */
?? ?
? TIMER0->CMD = TIMER_CMD_START; /*啟動計數器。如果這里沒有使能,定時器不會啟動,除非timerInit的enable清false*/
}
/**************************************************************************//**
?* @brief USART0 RX IRQ Handler
?*
?* Set up the interrupt prior to use
?*
?* Note that this function handles overflows in a very simple way.
?*
?*****************************************************************************/
void USART0_RX_IRQHandler(void)
{
? /* Check for RX data valid interrupt */
? if (usart->STATUS & UART_STATUS_RXDATAV)
? {
?? ??? ?usart0RxBuf.receivingFlg = true;//接收到數據標志
? ? /* Copy data into RX Buffer */
? ? usart0RxBuf.data[usart0RxBuf.rxByteCnt++] = USART_Rx(usart);
? ? /* Flag Rx overflow */
? ? if (usart0RxBuf.rxByteCnt >= BUFFERSIZE)//防止溢出,此處需要加上這個判斷
? ? {
? ? ? ?usart0RxBuf.rxByteCnt = 0;
? ? }
? ? /* Clear RXDATAV interrupt */
? ? USART_IntClear(USART0, UART_IF_RXDATAV);
? }
}
/**************************************************************************//**
?* @brief TIMER0_IRQHandler
?* Interrupt Service Routine TIMER0 Interrupt Line,20ms中斷一次
?*****************************************************************************/
void TIMER0_IRQHandler(void)
{?
? /* Clear flag for TIMER0 overflow interrupt */
? TIMER_IntClear(TIMER0, TIMER_IF_OF);
? if(usart0RxBuf.receivingFlg)
?? ?{
?? ? ? ++usart0RxBuf.delayMs;
?? ??? ? if(usart0RxBuf.delayMs > 4)//大于80ms則認為數據已經接收完成
?? ??? ? {
? ? ? ? ? ? ?usart0RxBuf.received = true;//接收完成標志觸發
?? ??? ??? ? usart0RxBuf.delayMs = 0;//數據接收延時清零
?? ??? ??? ? usart0RxBuf.receivingFlg = false;//數據接收標志清零
?? ??? ? }
?? ?}
}
/******************************************************************************
?* @brief ?Main function
?*
?*****************************************************************************/
int main(void)
{
? /* Initialize chip - handle erratas */
? CHIP_Init();
?? ?
?? ?/* Enable clock for HF peripherals */
? CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* 使用外部高頻晶振,外部晶振頻率是50MHz*/
?? ?
?? ?SysTickInit();//系統嘀嗒定時器初始化
?? ?
? Timer0Init();//定時器0初始化
?? ?
? /* Initialize UART peripheral */
? Usart0Init();
? while (1)
? {
?? ??? ?if(usart0RxBuf.received)//判斷是否接收完成
?? ??? ?{
? ? ? ? ? ? usart0RxBuf.received = false;//數據接收完成清零
?? ??? ??? ?UsartPutData(usart,usart0RxBuf.data,usart0RxBuf.rxByteCnt);//數據處理,這里把接收到的數據返回去
?? ??? ??? ?usart0RxBuf.rxByteCnt = 0;//數據長度清零
?? ??? ?}
? }
}
串口調試精靈數據發送和接收顯示:
方式2:串口+特定字符(如:\r\n作為一幀數據結尾)
不用定時器,直接在串口里面處理。程序實現如下所示。
#include <stdint.h>
#include <string.h>
#include "em_device.h"
#include "em_chip.h"
#include "em_emu.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_usart.h"
#include "bsp.h"
#include "em_timer.h"
#include "em_dma.h"
/* Declare a circular buffer structure to use for Rx and Tx queues */
#define BUFFERSIZE ? ? ? ? ?256
struct UASRT0Buffer
{
? uint8_t ?data[BUFFERSIZE]; //數據接收Buff
?? ?bool ? ? received;//接收完成標志
? uint16_t rxByteCnt; //接收數據長度
} usart0RxBuf;
uint32_t getCoreClock = 0;
USART_TypeDef ? ? * usart;
volatile uint32_t msTicks; /* counts 1ms timeTicks */
/***************************************************************************//**
?* SysTick_Handler
?*系統嘀嗒定時器中斷服務函數
?******************************************************************************/
void SysTick_Handler(void)
{
? msTicks++; ? ? ? /* increment counter necessary in Delay()*/
}
/***************************************************************************//**
?* @brief Delays number of msTick Systicks (typically 1 ms)
?* @param dlyTicks Number of ticks to delay
?******************************************************************************/
void Delay(uint32_t dlyTicks)
{
? uint32_t curTicks;
? curTicks = msTicks;
? while ((msTicks - curTicks) < dlyTicks) ;
}
/***************************************************************************//**
?* SysTick_Init
?*系統嘀嗒定時器中斷初始化
?******************************************************************************/
void SysTickInit(void)
{
?? ? getCoreClock = CMU_ClockFreqGet(cmuClock_CORE);
? ?/*設置系統嘀嗒定時器為1s*/
? ?if (SysTick_Config( getCoreClock / 1000))?
? ?{
? ? ? while (1) ;
? ?}
}
/******************************************************************************
* @brief ?UsartInit function
*串口0初始化
******************************************************************************/
void Usart0Init(void)
{
?? ?/* Enable clock for GPIO module (required for pin configuration) */
? CMU_ClockEnable(cmuClock_GPIO, true);
?? ?
? /* Enable clock for USART module */
? CMU_ClockEnable(cmuClock_USART0, true);
?? ?
? /* Configure GPIO pins */
? GPIO_PinModeSet(gpioPortE, 10, gpioModePushPull, 1);//串口0發送引腳配置為推挽輸出
? GPIO_PinModeSet(gpioPortE, 11, gpioModeInput, 1);//串口0接收引腳配置為輸入
? /* Setup USART0 in async mode */
?? ?usart ? = USART0;
?? ?USART_InitAsync_TypeDef uartInit = USART_INITASYNC_DEFAULT;
?? ?
? /* Prepare struct for initializing UART in asynchronous mode*/
? uartInit.enable ? ? ? = usartDisable; ? /* Don't enable UART upon intialization */
? uartInit.refFreq ? ? ?= 0; ? ? ? ? ? ? ?/* Provide information on reference frequency. When set to 0, the reference frequency is */
? uartInit.baudrate ? ? = 9600; ? ? ? ? /* Baud rate */
? uartInit.oversampling = usartOVS16; ? ? /* Oversampling. Range is 4x, 6x, 8x or 16x */
? uartInit.databits ? ? = usartDatabits8; /* Number of data bits. Range is 4 to 10 */
? uartInit.parity ? ? ? = usartNoParity; ?/* Parity mode */
? uartInit.stopbits ? ? = usartStopbits1; /* Number of stop bits. Range is 0 to 2 */
? uartInit.mvdis ? ? ? ?= false; ? ? ? ? ?/* Disable majority voting */
? uartInit.prsRxEnable ?= false; ? ? ? ? ?/* Enable USART Rx via Peripheral Reflex System */
? uartInit.prsRxCh ? ? ?= usartPrsRxCh0; ?/* Select PRS channel if enabled */
? /* Initialize USART with uartInit struct */
? USART_InitAsync(usart, &uartInit);
? /* Prepare UART Rx and Tx interrupts */
? USART_IntClear(usart, _UART_IF_MASK);
? USART_IntEnable(usart, UART_IF_RXDATAV);
? NVIC_ClearPendingIRQ(USART0_RX_IRQn);
? NVIC_ClearPendingIRQ(USART0_TX_IRQn);
? NVIC_EnableIRQ(USART0_RX_IRQn);
? NVIC_EnableIRQ(USART0_TX_IRQn);
? /* Enable I/O pins at USART0 location #0 */
? usart->ROUTEPEN = (1<<1)|(1<<0);//IO復用串口功能收發使能
?? ?
?? ?usart->ROUTELOC0 = (usart->ROUTELOC0& ~(_USART_ROUTELOC0_TXLOC_MASK| _USART_ROUTELOC0_RXLOC_MASK))//串口收發引腳映射
? ? ? ? ? ? ? ? ? ?|(_USART_ROUTELOC0_TXLOC_LOC0 << _USART_ROUTELOC0_TXLOC_SHIFT)
? ? ? ? ? ? ? ? ? ?|(_USART_ROUTELOC0_RXLOC_LOC0 << _USART_ROUTELOC0_RXLOC_SHIFT);
?? ?/* Enable UART */
? USART_Enable(usart, usartEnable);
}
/******************************************************************************
?* @brief ?uartPutData function
?*
?*****************************************************************************/
void UsartPutData(USART_TypeDef *usart,uint8_t * dataPtr, uint16_t dataLen)
{
?? ?while(dataLen--)//根據需要發送的數據長度判定要發出去多少個字節
?? ?{
?? ??? ??? ?while (!(usart->STATUS & USART_STATUS_TXBL));?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?
?? ??? ??? ?USART0->TXDATA = (uint32_t)(*(dataPtr++));
?? ??? ?}
}
/**************************************************************************//**
?* @brief USART0 RX IRQ Handler
?*
?* Set up the interrupt prior to use
?*
?* Note that this function handles overflows in a very simple way.
?*
?*****************************************************************************/
void USART0_RX_IRQHandler(void)
{
? /* Check for RX data valid interrupt */
? if (usart->STATUS & UART_STATUS_RXDATAV)
? {
? ? /* Copy data into RX Buffer */
? ? usart0RxBuf.data[usart0RxBuf.rxByteCnt] = USART_Rx(usart);
? ? if(usart0RxBuf.rxByteCnt >= 1) ?//因為有\r\n兩個字符,所以就要>=1
?? ??? ?{
?? ??? ??? ?if(( '\r' == usart0RxBuf.data[usart0RxBuf.rxByteCnt-1])&&('\n' == usart0RxBuf.data[usart0RxBuf.rxByteCnt]))
?? ??? ??? ?{
?? ??? ??? ??? ? usart0RxBuf.received = true;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?++usart0RxBuf.rxByteCnt;
? ? /* Flag Rx overflow */
? ? if (usart0RxBuf.rxByteCnt >= BUFFERSIZE)//防止溢出,此處需要加上這個判斷
? ? {
? ? ? ?usart0RxBuf.rxByteCnt = 0;
? ? }
? ? /* Clear RXDATAV interrupt */
? ? USART_IntClear(USART0, UART_IF_RXDATAV);
? }
}
/******************************************************************************
?* @brief ?Main function
?*
?*****************************************************************************/
int main(void)
{
? /* Initialize chip - handle erratas */
? CHIP_Init();
?? ?
?? ?/* Enable clock for HF peripherals */
// ?CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); /* 使用外部高頻晶振,外部晶振頻率是50MHz*/
?? ?CMU_HFRCOBandSet(cmuHFRCOFreq_64M0Hz);//64MHz
?? ?
?? ?SysTickInit();//系統嘀嗒定時器初始化
?? ?
? /* Initialize UART peripheral */
? Usart0Init();
? while (1)
? {
?? ??? ?if(usart0RxBuf.received)//判斷是否接收完成
?? ??? ?{
?? ??? ? ?usart0RxBuf.received = false;//數據接收完成清零
?? ??? ??? ?UsartPutData(usart,usart0RxBuf.data,usart0RxBuf.rxByteCnt);//數據處理,這里把接收到的數據返回去
?? ??? ??? ?usart0RxBuf.rxByteCnt = 0;//數據長度清零
?? ??? ?}
? }
}
串口調試精靈數據發送和接收顯示:
?
方式3:串口+帶有校驗的(如:帶有前導符+數據長度+校驗和+結束符)指令
不用定時器,直接在串口里面處理。實現方式同“方式2”。
?
總結
以上是生活随笔為你收集整理的第三课--EFM32GG11系列--串口接收不定长度数据的几种方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自主定义适合自己的Keil主题
- 下一篇: 编译器编译16bit单片机程序对数组da