打印
[RISC-V MCU 应用开发]

第九十二章:CH32V103应用教程——USART-奇偶校验

[复制链接]
3142|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
CH32V103应用教程——USART-奇偶校验

本章教程使用串口1(USART1)进行串口通信过程中的奇偶校验。

1、USART校验控制简介
通过设置USART控制寄存器1(USARTx_CTLR1)的位10 PCE位使能开启奇偶校验,具体解释如下图:
奇偶校验分为奇校验和偶校验,具体解释如下:
奇校验:此校验位使得一帧中的7或8个LSB数据以及校验位中’1’的个数为奇数。例如:数据=00110101,有4个’1’,如果选择奇校验(在USART_CR1中的PS= 1),校验位将是’1’。
偶校验:校验位使得一帧中的7或8个LSB数据以及校验位中’1’的个数为偶数。例如:数据=00110101,有4个’1’,如果选择偶校验(在USART_CR1中的PS= 0),校验位将是’0’。
关于CH32V103 USART具体信息,可参考CH32V103应用手册。USART标准库函数在第三章节已介绍,在此不再赘述。

2、硬件设计
本章教程使用串口1(USART1)进行串口通信并进行奇偶校验,具体连接方式如下:
硬件连线:PA9 —— WCH-Link RX引脚
      PA10 —— WCH-Link TX引脚

3软件设计
本章教程在第三章的基础上进行,串口改为选用串口1,串口奇偶校验具体程序如下:
usart.h文件
/*
* usart.h
*
*  Created on: May 20, 2021
*      Author: OWNER
*/

#ifndef USART_H_
#define USART_H_

#include "ch32v10x_conf.h"

#define  CHECK_NONE_ONE_STOP    1 //无校验位  1个停止位  1有效  0 无效
#define  CHECK_NONE_TWO_STOP    0 //无校验位  2个停止位  1有效  0 无效
#define  CHECK_EVEN    0          //偶数校验   1有效  0 无效
#define  CHECK_ODD     1          //奇数校验   1有效  0 无效

void USARTx_CFG(void);
void USARTx_SendByte(USART_TypeDef* pUSARTx, uint8_t data);
void USARTx_SendStr(USART_TypeDef* pUSARTx, char *str);
void USART1_IRQHandler(void);

#endif /* USART_H_ */
usart.h文件主要进行相关宏定义和函数声明;
usart.c文件
/*
* usart.c
*
*  Created on: May 20, 2021
*      Author: OWNER
*/
#include "usart.h"

void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

/*******************************************************************************
* Function Name  : USARTx_CFG
* Description    : Initializes the USART2 & USART3 peripheral.
* Input          : None
* Return         : None
*******************************************************************************/
void USARTx_CFG(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
    //RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

  /* USART1 TX-->A.9   RX-->A.10 */
    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);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = 115200;
//  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;

#if(CHECK_EVEN == 1)                                                                                            //如果定义了偶校验  数据位长度要改为9位
    USART_InitStructure.USART_WordLength = USART_WordLength_9b;
    USART_InitStructure.USART_Parity = USART_Parity_Even;
#endif

#if(CHECK_ODD == 1)                                                                                             //如果定义了奇校验  数据位长度要改为9位
    USART_InitStructure.USART_WordLength = USART_WordLength_9b;
    USART_InitStructure.USART_Parity = USART_Parity_Odd;
#endif

#if(CHECK_NONE_ONE_STOP==1)                                                                             //停止位为 一位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
#endif

#if(CHECK_NONE_TWO_STOP==1)                                                                             //停止位为 两位
    USART_InitStructure.USART_StopBits = USART_StopBits_2;
#endif

    USART_Init(USART1, &USART_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    USART_Cmd(USART1, ENABLE);
}

void USARTx_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
    USART_SendData(pUSARTx, data);
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

void USARTx_SendStr(USART_TypeDef* pUSARTx, char *str)
{
    uint8_t i = 0;
    do
    {
       USARTx_SendByte(pUSARTx, *(str+i));
       i++;
    }while(*(str+i) != '\0');
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}


/*******************************************************************************
* Function Name  : USART2_IRQHandler
* Description    : This function handles USART2 global interrupt request.
* Input          : None
* Return         : None
*******************************************************************************/
void USART1_IRQHandler(void)
{
    u16 tem = 0;

    if( (USART_GetITStatus( USART1, USART_IT_RXNE ) != RESET) &&(USART_GetFlagStatus( USART1, USART_FLAG_RXNE ) != RESET) )
    {
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);    //清除中断标志
        USART_ClearFlag(USART1, USART_FLAG_RXNE);

        if( (USART_GetFlagStatus( USART1, USART_FLAG_PE ) == RESET) )
        {
            tem = USART_ReceiveData( USART1 );
            USART_SendData( USART1, tem );
        }
        else
        {
            USARTx_SendStr(USART1, "error.\n");
        }
    }
    USART_GetFlagStatus( USART1, USART_FLAG_PE);
    USART_ReceiveData( USART1 );
}
usart.c文件主要进行串口奇偶校验的初始化配置以及中断服务函数中对奇偶校验的判断处理。在进行串口初始化的时候,注意要设置对应的奇偶校验,并且要将数据位长度改为9位,此处设置为奇校验。此外,还需要注意的是,串口状态寄存器在先读出USART_STATR,再读出USART_DATAR寄存器后,所有的状态位被清除,即RXNE和PE位也会被清零,所以在判断奇偶标志位错误的时候,应该在读取DR寄存器之前判断,从而判别奇偶校验的正确,具体见下图。
main.c文件
/********************************** (C) COPYRIGHT *******************************
* File Name          : main.c
* Author             : WCH
* Version            : V1.0.0
* Date               : 2020/04/30
* Description        : Main program body.
*******************************************************************************/

#include "debug.h"
#include "usart.h"

/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Return         : None
*******************************************************************************/
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    USARTx_CFG();                                                  /* USART1 INIT */
    USARTx_SendStr(USART1, "This is a test data.\n");
    while(1)
    {
    }
}
main.c文件主要进行函数初始化。

4下载验证
将编译好的程序下载到开发版并复位,串口打印如下:
程序中配置为奇校验,将串口调试工具设置为奇校验,通信正常,具体如下:
若串口调试工具配置为偶校验或无校验,通信错误,返回error,具体如下:

CH32V USART-奇偶校验.rar

441.87 KB

使用特权

评论回复

相关帖子

沙发
jcky001| | 2021-5-28 09:03 | 只看该作者
很棒,研究一下

使用特权

评论回复
板凳
643757107| | 2021-5-31 11:15 | 只看该作者
奇偶校验一直没用过。如果开启了奇偶校验,当出现错误时候,是要自己编程处理重发,还是会自动重发?

使用特权

评论回复
评论
RISCVLAR 2021-6-11 14:01 回复TA
你好,如果出现校验错误,需要自己在程序中进行相关配置重发,不会自动重发。当产生奇偶校验错误,会产生相应标志位,可根据相应标志位进行配置。 
地板
flycamelaaa| | 2021-6-2 10:52 | 只看该作者
楼上的小伙伴问题问的很好,我也想知道

使用特权

评论回复
5
skyred| | 2021-6-11 13:13 | 只看该作者
恩,学习一下,一直用的CRC

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

132

主题

293

帖子

41

粉丝