0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

如何來編寫一個串口收發(fā)程序

汽車電子技術 ? 來源:物聯(lián)網(wǎng)知識 ? 作者: 跋扈洋 ? 2023-01-20 16:43 ? 次閱讀

介紹

串口(UART通用異步收發(fā)器,TTL)通訊是一種設備間的串行全雙工通訊方式。由于UART是異步傳輸,沒有傳輸同步時鐘,為了保證數(shù)據(jù)的正確性,UART采用16倍數(shù)據(jù)波特率的時鐘進行采樣。因為它簡便捷,因此大部分電子設備都支持該通訊方式工程師在調(diào)試設備時也經(jīng)常使用該方式輸出調(diào)試信息。

本文詳細的介紹如何來編寫一個串口收發(fā)程序,我們采用常用的收發(fā)邏輯,發(fā)送直接編寫函數(shù)進行實現(xiàn),而接收使用中斷進行完成。接收中斷使用接收到一個字節(jié)和一幀數(shù)據(jù)兩種中斷觸發(fā)方式。

USART中斷

USART 有多個中斷請求事件。微信截圖_20230105161930.png

之所以介紹這個USART中斷請求,是因為很多人在初學階段,對串口怎么判斷串口中斷的狀態(tài)不太了解,所以我這里重點來介紹一下。

一般在我們開始和配置完串口中斷后,進入串口中斷處理程序的情況會有很多,我們也可以自己選擇打開哪些串口中斷情況。一般情況下,我們在接受時主要使用的中斷事件標志是RXNE和IDLE。

RXNE是接收中斷,每接收一個字節(jié)都會出發(fā)這個中斷,也是我們用的最頻繁的中斷請求。

IDLE 是空閑中斷,每接收完一幀數(shù)據(jù),總線就會暫時空閑,就會觸發(fā)這個中斷。

串口狀態(tài)

串口的狀態(tài)可以通過狀態(tài)寄存器 USART_SR 讀取。USART_SR 的各位描述如下:微信截圖_20230105161930.png

這里我們關注一下兩個位,第 5、6 位 RXNE 和 TC。

RXNE(讀數(shù)據(jù)寄存器非空),當該位被置 1 的時候,就是提示已經(jīng)有數(shù)據(jù)被接收到了,且可以讀出來了。這時候我們要做的就是盡快去讀取 USART_DR,通過讀 USART_DR 可以該位清零,也可以向該位寫 0,直接清除。

TC(發(fā)送完成),當該位被置位的時候,表示 USART_DR 內(nèi)的數(shù)據(jù)已經(jīng)被發(fā)送完成了。果設置了這個位的中斷,則會產(chǎn)生中斷。該位也有兩種清零方式:

  1. 讀 USART_SR,USART_DR。
  2. 直接向該位寫 0。

實例

需求分析

本項目主要編寫一個串口收發(fā)的實例。使用STM32F103C8T6充當MCU,在PC上使用串口調(diào)試助手充當上位機。每次PC向MCU下發(fā)一幀數(shù)據(jù), MCU每接收一個字節(jié)數(shù)據(jù),檢查一下數(shù)據(jù)中是否有指令0x23,當接收到指令0x23的時候,MCU向上位機發(fā)送“PC”。當一幀數(shù)據(jù)接收完畢后,MCU向上位機發(fā)送“Receive a frame data”.

串口初始化

串口初始化的一般步驟可以總結(jié)為如下幾個步驟:

  1. 串口時鐘使能,GPIO 時鐘使能。
  2. 設置引腳復用器映射:調(diào)用 GPIO_PinAFConfig 函數(shù)。
  3. GPIO 初始化設置:要設置模式為復用功能。
  4. 串口參數(shù)初始化:設置波特率,字長,奇偶校驗等參數(shù)。
  5. 開啟中斷并且初始化 NVIC,使能中斷(如果需要開啟中斷才需要這個步驟)。
  6. 使能串口。
#include "usart.h"
#include 
#include "stm32f1xx_hal.h
UART_HandleTypeDef huart3
void MX_USART3_UART_Init(void)


  huart3.Instance = USART3;
  huart3.Init.BaudRate = 115200;
  huart3.Init.WordLength = UART_WORDLENGTH_8B;
  huart3.Init.StopBits = UART_STOPBITS_1;
  huart3.Init.Parity = UART_PARITY_NONE;
  huart3.Init.Mode = UART_MODE_TX_RX;
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart3.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart3) != HAL_OK)
  {
    Error_Handler()
  __HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE);//接收中斷使能
  __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);//空閑中斷使能 
}


void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)


  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART3)
  {
    __HAL_RCC_USART3_CLK_ENABLE()
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**USART3 GPIO Configuration
    PB10     ------> USART3_TX
    PB11     ------> USART3_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct)
    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    HAL_NVIC_SetPriority(USART3_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART3_IRQn);

我們平時需要改的其實就是串口的一些參數(shù)配置。

  • BaudRate:波特率
  • WordLength;:字長
  • StopBits:停止位
  • Parity:奇偶校驗
  • Mode:收/發(fā)模式設置
  • HwFlowCtl:硬件流設置
  • OverSampling:過采樣設置

串口發(fā)送

串口發(fā)送這里使用的非中斷發(fā)送方式。

/*******************************************************************************
  * @函數(shù)名稱  USART_Send
  * @函數(shù)說明   發(fā)送信息
  * @輸入?yún)?shù)   _UART:串口號
      data:要發(fā)送的信息的首地址
      len:發(fā)送的長度
  * @輸出參數(shù)   無
  * @返回參數(shù)   無
*******************************************************************************/
void USART_Send(USART_TypeDef *_UART,uint8_t *data,uint8_t len)
{
  for(int i;i

主要使用的是HAL_UART_Transmit(&huart3,&Res,1,0Xffff);

這是一個阻塞的發(fā)送函數(shù),無需重復判斷串口是否發(fā)送完成。發(fā)送每個字符,直到遇空字符才停止發(fā)送。其中第一個參數(shù)是串口號,第二個參數(shù)是要發(fā)送的數(shù)據(jù)起始地址,第三個是要發(fā)送的數(shù)據(jù)長度,第四個超時時間(超過此長度仍未發(fā)送成功則阻塞完畢,停止發(fā)送,函數(shù)執(zhí)行完畢)。

串口接收

這里串口接收使用的是中斷的方式。

中斷的類別在文章的最上邊已經(jīng)介紹過。我們在初始化時設定觸發(fā)中斷的類型。本文中設置的

__HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE);//接收中斷使能
__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);//空閑中斷使能

代表只有接收數(shù)據(jù)和空閑中斷會觸發(fā)。

在stm32f1xx_it.c中有我們的串口中斷處理函數(shù)。我們將這個函數(shù)進行重構(gòu)。

void USART3_IRQHandler(void)
{
  uint8_t Res;
if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE)!=RESET
{
  HAL_UART_Receive(&huart3,&Res,1,0Xffff); 
 if(Res==0x23)  
  printf("PC");
}
else if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)//空閑中斷(代表這一幀數(shù)據(jù)傳輸完了)
{
  printf("Receive a frame data.");
  __HAL_UART_CLEAR_IDLEFLAG(&huart3);
}

這里面的幾個重點,我們來一一介紹。

首先是判斷標志位,我們使用HAL庫中的__HAL_UART_GET_FLAG()函數(shù),里面有兩個參數(shù),前者是串口句柄,后者是具體哪個標志位。

if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE)!=RESET)用來檢測是否檢測到有單個字節(jié)的中斷。

if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)用來檢測是否有空閑中斷(代表這一幀數(shù)據(jù)傳輸完了)。

重定向printf和scanf

還有一點需要注意的,使用 fput 和 fgetc 函數(shù)達到重定向 C 語言標準庫輸入輸出函數(shù)必須在 MDK 的工程選項把“Use MicroLIB”勾選上, MicoroLIB 是缺省 C 庫的備選庫,它對標準 C 庫進行了高度優(yōu)化使代碼更少,占用更少資源

為使用 printf、 scanf 函數(shù)需要在文件中包含 stdio.h 頭文件。

/**
  * 函數(shù)功能: 重定向c庫函數(shù)printf
  * 輸入?yún)?shù): 無
  * 返 回 值: 無
  * 說    明:無
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}

/**
  * 函數(shù)功能: 重定向c庫函數(shù)getchar,scanf
  * 輸入?yún)?shù): 無
  * 返 回 值: 無
  * 說    明:無
  */
int fgetc(FILE *f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart3, &ch, 1, 0xffff);
  return ch;
}

效果

  1. PC下發(fā):11 22 33 44

    微信截圖_20230105161930.png

  2. PC下發(fā):12 23 34 45

    微信截圖_20230105161930.png

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 收發(fā)器
    +關注

    關注

    10

    文章

    3428

    瀏覽量

    106008
  • 串口
    +關注

    關注

    14

    文章

    1554

    瀏覽量

    76528
  • uart
    +關注

    關注

    22

    文章

    1235

    瀏覽量

    101404
收藏 人收藏

    評論

    相關推薦

    【紫光同創(chuàng)國產(chǎn)FPGA教程】【第五章】串口收發(fā)實驗

    本文主要講解如何編寫FPGA串口通信的收發(fā)程序,在程序中使用了狀態(tài)機,是學習狀態(tài)機的重要實驗。
    的頭像 發(fā)表于 02-04 13:23 ?6732次閱讀
    【紫光同創(chuàng)國產(chǎn)FPGA教程】【第五章】<b class='flag-5'>串口</b><b class='flag-5'>收發(fā)</b>實驗

    編寫一個QT程序

    學習種編程語言或編程環(huán)境,通常會先編寫“Hello World”程序。我們也用 Qt Creator
    發(fā)表于 11-21 10:41 ?1026次閱讀

    如何去編寫種基于Atmega8單片機的串口收發(fā)程序?

    如何去編寫種基于Atmega8單片機的串口收發(fā)程序?有大神遇到過這個問題嗎
    發(fā)表于 07-08 06:06

    如何利用AVR編寫簡單的串口通信的程序

    如何利用AVR編寫簡單的串口通信的程序?
    發(fā)表于 11-02 08:06

    STM32的串口收發(fā)程序如何編寫

    STM32的串口收發(fā)程序如何編寫?
    發(fā)表于 12-16 07:34

    怎樣去編寫串口數(shù)據(jù)接收程序

    【嵌入式】串口數(shù)據(jù)接收程序1.題目詳情2.代碼詳解1.題目詳情編寫串口數(shù)據(jù)接收
    發(fā)表于 12-21 06:12

    分享串口收發(fā)的小程序功能

    串口收發(fā)的小程序功能就是串口數(shù)據(jù)的收發(fā);設置標題
    發(fā)表于 01-18 07:53

    求大佬分享stm32自收發(fā)串口通信程序

    求大佬分享stm32自收發(fā)串口通信程序
    發(fā)表于 02-18 07:40

    VHDL設計的串口通信程序

    本模塊的功能是驗證實現(xiàn)和PC機進行基本的串口通信的功能。需要在PC機上安裝串口調(diào)試工具來驗證程序的功能。
    發(fā)表于 06-05 12:03 ?2859次閱讀

    labview串口編寫中可能用到的程序

    串口編寫中可能用到的程序
    發(fā)表于 01-03 16:49 ?10次下載

    如何使用Python編寫簡單的程序

    按照軟件行業(yè)傳統(tǒng)習慣,當你學習種新的編程語言如Python時,首先編寫“Hello World! ”程序。請執(zhí)行以下步驟,以創(chuàng)造你的“
    的頭像 發(fā)表于 01-16 15:21 ?2.2w次閱讀

    verilog編寫UART串口程序下載

    收發(fā)程序寫在.v文件中,已經(jīng)在板子上實驗過,收發(fā)正常
    發(fā)表于 12-21 18:08 ?0次下載
    verilog<b class='flag-5'>編寫</b>UART<b class='flag-5'>串口</b><b class='flag-5'>程序</b>下載

    如何編寫一個hello world程序

    本文簡單介紹如何編寫一個hello world程序,以及程序是如何被執(zhí)行的
    的頭像 發(fā)表于 03-02 17:31 ?8402次閱讀
    如何<b class='flag-5'>編寫</b>第<b class='flag-5'>一個</b>hello world<b class='flag-5'>程序</b>

    串口工具監(jiān)聽多路串口收發(fā)方案

    當我們僅有串口工具時,如何通過簡單的方式,來做到串口工具,監(jiān)聽
    的頭像 發(fā)表于 03-22 15:46 ?3457次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>個</b><b class='flag-5'>串口</b>工具監(jiān)聽多路<b class='flag-5'>串口</b><b class='flag-5'>收發(fā)</b>方案

    vim編寫程序后怎么運行

    當你用 Vim 編寫程序后,你需要執(zhí)行系列步驟來運行程序。下面是詳盡的說明: 保存文件:
    的頭像 發(fā)表于 11-28 15:27 ?3733次閱讀