打印
[单片机芯片]

【沁恒CH32V307 RISC-V开发板测评】UART测试

[复制链接]
737|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
最近想玩一下,CH32V307这款开发板,主要看到是RISC-V架构,并且功能比较丰富,所以就想来看看这个开发板功能强大。先来玩玩串口。
一、串口介绍
1、串口的作用
1)设备互联
单片机的串口像一个小型“数据中转站”,允许它与电脑交换调试信息(如温度数据)、控制传感器(如读取湿度)、连接WiFi模块等;就好像智能家居中,单片机通过串口接收手机指令,再控制灯泡开关
2)实现远距离通信
串口只需​​两根数据线​​(TXD发送、RXD接收)和一根地线(GND),比并行通信(需8根以上)更省硬件成本,且可通过RS485等标准传输到几百米外。
2、工作原理
想象两个人用摩斯密码发电报:
1)数据拆解​​:单片机把数据(如字母“A”)拆成二进制位(如01000001),​​一位一位发送​​,像逐颗发糖。
2)数据打包​​:每帧数据像一个小包裹,包含:
起始位​​(低电平):喊一声“开始!”(占用1位);
数据位​​(5-9位):实际传输的信息(如8位二进制);
停止位​​(高电平):喊一声“结束!”(占用1-2位)(可选校验位:防传输错误)
3)同步节奏(波特率)​​双方需约定​​传输速度​​(波特率),如9600bps=每秒传9600位。若速度不一致,接收方会“听错”数据。
4)全双工通信​​发送(TXD)和接收(RXD)可​​同时进行​​,像双向车道,允许一边说话一边听对方回复
3、串口的优点
简单可靠​​:2根线解决通信问题,抗干扰强(尤其RS485)。
资源占用少​​:单片机内部有专用硬件(UART),编程时只需配置寄存器(如SCON)。
生态丰富​​:几乎所有模块(GPS、蓝牙等)都支持串口指令控制
总之,串口就是单片机与外界对话的“嘴巴”和“耳朵”,用最低成本实现高效数据交换,堪称嵌入式系统的​​通信基石
4、CH32V307串口的特点
1)全双工或半双工的同步或异步通信
2)NRZ 数据格式
3)分数波特率发生器,最高 9Mbps
4)可编程数据长度
5)可配置的停止位
6)支持 LIN,IrDA 编码器,智能卡
7)支持 DMA
8)多种中断源
二、代码实现
本次主要通过串口中断接收数据,另外使用两个串口进行数据互发,看看数据是否能够正常接收
1、中断接收和配置两个串口,一个串口发送,一个串口接收
代码编写
/********************************** (C) COPYRIGHT *******************************
* File Name          : main.c
* Author             : WCH
* Version            : V1.0.0
* Date               : 2021/06/06
* Description        : Main program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/

/*
*@Note
USART Print debugging routine:
USART1_Tx(PA9).
This example demonstrates using USART1(PA9) as a print debug port output.

*/

#include "debug.h"


/* Global typedef */

/* Global define */
#define RX_BUF_SIZE 512
#define TX_BUF_SIZE 512

#define USART_MODE_DMA 0
/* Global Variable */
void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void SysTick_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

void USART2_Init(void);
void DMA_INIT(void);
void SYSTICK_Init_Config(u_int64_t ticks);

uint8_t g_usart2RxBuf[RX_BUF_SIZE] = {0};
uint8_t g_usart2TxBuf[TX_BUF_SIZE] = {0};
uint16_t g_usart2RxCnt = 0;
uint16_t g_usart2TxCnt = 0;
uint8_t g_usart2SendOK = 1;
volatile uint8_t g_usart2RecvOK = 0;
uint8_t g_rxTimeOut = 10;
/*********************************************************************
* @fn      main
*
* [url=home.php?mod=space&uid=247401]@brief[/url]   Main program.
*
* [url=home.php?mod=space&uid=266161]@return[/url]  none
*/
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    SystemCoreClockUpdate();
    Delay_Init();
    USART_Printf_Init(115200);  
    printf("SystemClk:%d\r\n",SystemCoreClock);
    printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
    SYSTICK_Init_Config((SystemCoreClock / 1000)-1);
    #if USART_MODE_DMA
    DMA_INIT();
    #else

    #endif

    USART2_Init();

    #if USART_MODE_DMA
    USART_DMACmd(USART2, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
    #else

    #endif
    while(1)
    {
        if (g_usart2RecvOK) {
            g_usart2RecvOK = 0;
            printf("recved data:\r\n");
            for(uint16_t i = 0;i< g_usart2RxCnt;i++) {
                printf("%c",g_usart2RxBuf[i]);
            }
            g_usart2RxCnt = 0;
            printf("\r\n");
        }
    }
}

/*********************************************************************
* @fn      USART2_Init
*
* @brief   Initializes the USART2 peripheral.
*
* @return  none
*/
void USART2_Init(void) {
    GPIO_InitTypeDef  GPIO_InitStructure = {0};
    USART_InitTypeDef USART_InitStructure = {0};
    NVIC_InitTypeDef  NVIC_InitStructure = {0};

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    /* USART2 TX-->A.2   RX-->A.3 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    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;

    USART_Init(USART2, &USART_InitStructure);
    #if USART_IDLE_RECV_MODE
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
    #else
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
    #endif
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_Cmd(USART2, ENABLE);
}

/*********************************************************************
* @fn      DMA_INIT
*
* @brief   Configures the DMA for USART2 & USART3.
*
* @return  none
*/
void DMA_INIT(void)
{
    DMA_InitTypeDef DMA_InitStructure = {0};
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel7);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DATAR); /* USART2->DATAR:0x40004404 */
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_usart2TxBuf;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = TX_BUF_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel7, &DMA_InitStructure);

    DMA_DeInit(DMA1_Channel6);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DATAR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_usart2RxBuf;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = RX_BUF_SIZE;
    DMA_Init(DMA1_Channel6, &DMA_InitStructure);
}

void USART2_Send_Data(uint8_t *data,uint16_t size) {
    while(!g_usart2SendOK);
    USART_SendData(USART2, *data++);
    g_usart2SendOK = 0;
}
/*********************************************************************
* @fn      USART2_IRQHandler
*
* @brief   This function handles USART2 global interrupt request.
*
* @return  none
*/
void USART2_IRQHandler(void)
{
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    {
        USART_ClearFlag(USART2,USART_FLAG_RXNE);
        if(g_usart2RxCnt > RX_BUF_SIZE) {
            g_usart2RxCnt = 0;
        } else {
            g_rxTimeOut = 1;
            g_usart2RxBuf[g_usart2RxCnt++] = USART_ReceiveData(USART2);
        }
    }
}

/*********************************************************************
* @fn      SYSTICK_Init_Config
*
* @brief   SYSTICK_Init_Config.
*
* @return  none
*/
void SYSTICK_Init_Config(u_int64_t ticks)
{
    SysTick->SR &= ~(1 << 0);//clear State flag
    SysTick->CMP = ticks;
    SysTick->CNT = 0;
    SysTick->CTLR = 0xF;

    NVIC_SetPriority(SysTicK_IRQn, 15);
    NVIC_EnableIRQ(SysTicK_IRQn);
}

/*********************************************************************
* @fn      SysTick_Handler
*
* @brief   SysTick_Handler.
*
* @return  none
*/
void SysTick_Handler(void)
{
    if(SysTick->SR == 1)
    {
        SysTick->SR = 0;//clear State flag
        if (g_rxTimeOut) {
            g_rxTimeOut--;
            if (!g_rxTimeOut)
            {
                g_usart2RecvOK = 1; //一帧接收完成
            }
        }
    }
}
2、下载验证
1)串口助手设置100ms定时发送

接收和发送都为59条数据

2)串口助手设置5ms定时发送
波特率为115200 bit/s 以一个起始位、一个停止位计算 传输一个字节;
传输1个bit位需要 1/115200 = 8.6805us;
传输10bit = 86.805us; 那么两个字节之间的间隔为一个停止位和起始位
36个字节传输需要:86.805*36 = 3.125ms
再加上每次1ms的延时,以及printf的执行,会导致有些打印出来,因此只能搜索is来统计数据




串口中断处理程序

综上:间隔100ms和间隔5ms发送和接收都是没有问题,可见CH32V307上手还是很快的,直接参考例程即可上手,快速开发。






使用特权

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

本版积分规则

4

主题

11

帖子

0

粉丝