天天看點

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

1. 簡介

序列槽全稱:Universal synchronous asynchronous receiver transmitter,中文名稱:通用同步異步串行接收發送器。序列槽可用于接收和發送資料,可以用作跟其他裝置通訊,如藍牙子產品、GSM子產品、GPS子產品等。

序列槽中最常見的是RS-232,共有9根線用于通訊,但常用的僅3根線:RXD、TXD、GND。其中RXD用于接收,TXD用于發送,GND為信号地線,兩個通訊裝置之間的收發信号(RXD與TXD)應交叉相連。

2. 基本概念

  • 波特率:序列槽異步通訊中由于沒有時鐘信号,是以兩個通訊裝置之間需要約定好波特率,即每個碼元的長度,以便對信号進行解碼,常見的波特率為4800、9600、115200 等。波特率越高傳輸速度越快,但出錯的機率要更大。
  • 通訊的起始和停止信号:序列槽通訊的一個資料包從起始信号開始,直到停止信号結束。資料包的起始信号由一個邏輯 0 的資料位表示,而資料包的停止信号可由 0.5、1、1.5或 2個邏輯 1的資料位表示,隻要雙方約定一緻即可。
  • 有效資料:在資料包的起始位之後緊接着的就是要傳輸的主體資料内容,也稱為有效資料,有效資料的長度常被約定為 5、6、7或 8位長。
  • 資料校驗:在有效資料之後,有一個可選的資料校驗位。由于資料通信相對更容易受到外部幹擾導緻傳輸資料出現偏差,可以在傳輸過程加上校驗位來解決這個問題。校驗方法有奇校驗(odd)、偶校驗(even)、0校驗(space)、1校驗(mark)以及無校驗(noparity)。奇校驗要求有效資料和校驗位中“1”的個數為奇數,偶校驗與奇校驗要求剛好相反,要求幀資料和校驗位中“1”的個數為偶數,0校驗是不管有效資料中的内容是什麼,校驗位總為“0”,1校驗是校驗位總為“1”。
  • 常用的設定:波特率9600,8位資料位,1位停止位,無校驗位,無硬體流控。

序列槽USART分為兩部分,初始化和處理。

1. 初始化分三步:GPIO、通用中斷、USART。

1.1. GPIO:時鐘、引腳、輸入輸出模式、端口初始化

  • 時鐘:需要同時使能GPIO時鐘
  • 引腳:需要選擇指定的引腳
  • 輸入輸出模式:TX引腳選擇複用推挽模式,RX引腳選擇浮空輸入模式
  • 端口初始化:初始化指定的端口

1.2. 通用中斷:優先級分組、中斷源、優先級、使能

  • 優先級分組:設定合适的優先級分組
  • 中斷源:選擇指定的中斷源:USART1_IRQn
  • 優先級:設定合适的優先級
  • 使能:調用庫函數即可,可選擇使能多個中斷,一般情況下隻使能接收中斷。

1.3. USART:時鐘、波特率、資料字長、停止位、校驗位、硬體流控制、工作模式、初始化、使能。

  結構體

typedef struct {
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits; 
uint16_t USART_Parity; 
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl; 
} USART_InitTypeDef;
           
  • 時鐘:需要使能USART1時鐘

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  • 波特率:一般可選的設定項包括4800、9600、115200等,常用的波特率為9600。

USART_InitStructure.USART_BaudRate = 9600;

  • 資料字長:可選8位或9位,常用的是8位。

USART_InitStructure.USART_BaudRate = 9600;

  • 停止位:可選0.5、1、1.5、2個,常用的是1個停止位。

USART_InitStructure.USART_BaudRate = 9600;

  • 奇偶校驗:可選無校驗、奇校驗和偶校驗,常用的是無校驗。

USART_InitStructure.USART_Parity = USART_Parity_No;

  • 模式:可選發送、接收,或者同時啟用,一般都是同時啟用。

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  • 硬體流控:可選有使能RTS、使能CTS、同時使能、不使能,一般選擇不使能。

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  • 初始化配置

USART_Init(USART1, &USART_InitStructure);

  • 使能

USART_Cmd(USART1, ENABLE);

2. 處理

處理分為接收和發送。

接收處理通常放在中斷中,中斷服務函數名稱為USART1_IRQHandler(),調用庫函數USART_ReceiveData()得到接收的資料,并自動清除接收中斷标志位;

發送直接調用庫函數USART_SendData()即可,發送完成之後會調用函數來擷取相應标志來實作發送完成等待功能,即USART_SendData()函數傳回時,相應的資料已經確定發送完成,并可發送下一個資料,發送不同類型的資料可以封裝成不同的函數,但最終都是調用USART_SendData()函數。

接收:

// 序列槽中斷服務函數
void USART1_IRQHandler(void)
{
    uint8_t ucTemp;
    if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
    {    
        ucTemp = USART_ReceiveData(USART1);
    }     
}
           

發送:

//發送一個位元組
void Usart_SendByte(USART_TypeDef * pUSARTx, uint8_t ch)
{
    //發送一個位元組資料到USART
    USART_SendData(pUSARTx,ch);
    //等待發送資料寄存器為空,即發送完成
    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET); 
}
//發送一個數組
void Usart_SendArray(USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
//發送字元串
void Usart_SendString(USART_TypeDef * pUSARTx, char *str)
           
完整代碼(僅自己編寫的部分)
void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    /* 嵌套向量中斷控制器組選擇 */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    /* 配置USART為中斷源 */
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    /* 搶斷優先級*/
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    /* 子優先級 */
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    /* 使能中斷 */
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    /* 初始化配置NVIC */
    NVIC_Init(&NVIC_InitStructure);
}

void USART_Config(uint32_t baudrate)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    // 打開序列槽GPIO的時鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 打開序列槽外設的時鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    // 将USART Tx的GPIO配置為推挽複用模式
    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);

  // 将USART Rx的GPIO配置為浮空輸入模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置序列槽的工作參數
    // 配置波特率
    USART_InitStructure.USART_BaudRate = baudrate;
    // 配置 幀資料字長
    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(USART1, &USART_InitStructure);

    // 序列槽中斷優先級配置
    NVIC_Configuration();

    // 使能序列槽接收中斷
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    // 使能序列槽
    USART_Cmd(USART1, ENABLE);
}

//發送一個位元組
void Usart_SendByte(USART_TypeDef * pUSARTx, uint8_t ch)
{
    //發送一個位元組資料到USART
    USART_SendData(pUSARTx,ch);
    //等待發送資料寄存器為空,即發送完成
    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

//發送數組
void Usart_SendArray(USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
    uint8_t i;

    for(i = 0; i < num; i++)
    {
        /* 發送一個位元組資料到USART */
        Usart_SendByte(pUSARTx, array[i]);
    }
    /* 等待發送完成 */
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC)==RESET);
}

//發送字元串
void Usart_SendString(USART_TypeDef * pUSARTx, char *str)
{
    uint32_t k = 0;

    do
    {
        Usart_SendByte(pUSARTx, *(str + k));
        k++;
    } while(*(str + k)!='0');

    /* 等待發送完成 */
    while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}

//發送16位數
void Usart_SendHalfWord(USART_TypeDef * pUSARTx, uint16_t ch)
{
    uint8_t temp_h, temp_l;

    /* 取出高八位 */
    temp_h = (ch & 0xFF00) >> 8;
    /* 取出低八位 */
    temp_l = ch & 0xFF;

    /* 發送高八位 */
    USART_SendData(pUSARTx, temp_h);
    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);

    /* 發送低八位 */
    USART_SendData(pUSARTx, temp_l);
    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

// 序列槽中斷服務函數
void USART1_IRQHandler(void)
{
    uint8_t ucTemp;

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        ucTemp = USART_ReceiveData(USART1);
        USART_SendData(USART1, ucTemp);
    }
}

int main(void)
{
    USART_Config(9600);

    Usart_SendString(USART1, "Hello World!n");

    while(1)
    {
    }
}
           

仿真結果

1. 發送

編譯完成後,點選

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

開始仿真,點選

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

,打開序列槽監視序列槽(點選右側的箭頭可以選擇第幾個序列槽),然後運作程式,可以在序列槽監視視窗看到序列槽發送的資訊。

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

2. 接收

如果想要仿真序列槽接收,需要使用虛拟序列槽軟體vspd,下載下傳安裝完成後,運作該軟體:

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

可以看到左側有COM1-5共 5個實體序列槽,點選右側的添加端口,可以添加COM6和COM7兩個虛拟序列槽,并自動連接配接這兩個序列槽。

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

此時可以打開2個序列槽工具,分别設定為COM6和COM7,并分别發送資料,看看對方是否能夠正常接收,如果可以,表示虛拟序列槽添加并連接配接成功,此時在序列槽工具中關閉COM6。

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

運作KEIL,并開始仿真後,在COMMAND序列槽中輸入

MODE COM6 9600,0,8,1

ASSIGN COM6 <S1IN> S1OUT

第一條指令設定COM6波特率9600,無校驗位,8個資料位,1個停止位,注意這裡的設定應該與程式中序列槽的設定保持一緻。

第二條指令将COM6和單片機的第一個序列槽進行綁定,即單片機第一個序列槽的收發資料通過計算機的COM6進行收發。

此時在序列槽工具打開COM7,并通過序列槽工具發送資料,程式即可接收到發送的資料。

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

從上圖可以看到從COM7發送了一個A給單片機,單片機接收到了A,并将A又發送出去,COM7接收到了A。

是以,通過虛拟序列槽軟體,即可在無開發闆、無序列槽線、無序列槽裝置的情況下,通過序列槽工具即可調試序列槽接收及發送程式,實作純軟體環境調試。

學習資料分享交流群:1093776732 入群有全套學習視訊資料電子書免費贈送!

參考資料:

嵌入式開發直播課 - STM32 USART序列槽的應用​www.makeru.com.cn

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

物聯網開發入門直播課 - 基于STM32講解序列槽操作​www.makeru.com.cn

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

物聯網開發入門直播課 - 通過Z-stack協定棧實作序列槽透傳​www.makeru.com.cn 嵌入式開發直播課 - 帶你揭曉STM32定時器深藏不露的絕技​www.makeru.com.cn

vc++ cserialport 打開多個序列槽_STM32之USART序列槽

物聯網STM32入門 - 帶你揭曉STM32定時器深藏不露的絕技​www.makeru.com.cn