[单片机芯片] 【沁恒CH32V307 RISC-V开发板测评】UART测试

[复制链接]
3538|0
 楼主| 星享社 发表于 2025-7-23 22:57 | 显示全部楼层 |阅读模式
最近想玩一下,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、中断接收和配置两个串口,一个串口发送,一个串口接收
代码编写
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2021/06/06
  6. * Description        : Main program body.
  7. *********************************************************************************
  8. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
  9. * Attention: This software (modified or not) and binary are used for
  10. * microcontroller manufactured by Nanjing Qinheng Microelectronics.
  11. *******************************************************************************/

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

  17. */

  18. #include "debug.h"


  19. /* Global typedef */

  20. /* Global define */
  21. #define RX_BUF_SIZE 512
  22. #define TX_BUF_SIZE 512

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

  27. void USART2_Init(void);
  28. void DMA_INIT(void);
  29. void SYSTICK_Init_Config(u_int64_t ticks);

  30. uint8_t g_usart2RxBuf[RX_BUF_SIZE] = {0};
  31. uint8_t g_usart2TxBuf[TX_BUF_SIZE] = {0};
  32. uint16_t g_usart2RxCnt = 0;
  33. uint16_t g_usart2TxCnt = 0;
  34. uint8_t g_usart2SendOK = 1;
  35. volatile uint8_t g_usart2RecvOK = 0;
  36. uint8_t g_rxTimeOut = 10;
  37. /*********************************************************************
  38. * @fn      main
  39. *
  40. * [url=home.php?mod=space&uid=247401]@brief[/url]   Main program.
  41. *
  42. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  43. */
  44. int main(void)
  45. {
  46.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  47.     SystemCoreClockUpdate();
  48.     Delay_Init();
  49.     USART_Printf_Init(115200);  
  50.     printf("SystemClk:%d\r\n",SystemCoreClock);
  51.     printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
  52.     SYSTICK_Init_Config((SystemCoreClock / 1000)-1);
  53.     #if USART_MODE_DMA
  54.     DMA_INIT();
  55.     #else

  56.     #endif

  57.     USART2_Init();

  58.     #if USART_MODE_DMA
  59.     USART_DMACmd(USART2, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
  60.     #else

  61.     #endif
  62.     while(1)
  63.     {
  64.         if (g_usart2RecvOK) {
  65.             g_usart2RecvOK = 0;
  66.             printf("recved data:\r\n");
  67.             for(uint16_t i = 0;i< g_usart2RxCnt;i++) {
  68.                 printf("%c",g_usart2RxBuf[i]);
  69.             }
  70.             g_usart2RxCnt = 0;
  71.             printf("\r\n");
  72.         }
  73.     }
  74. }

  75. /*********************************************************************
  76. * @fn      USART2_Init
  77. *
  78. * @brief   Initializes the USART2 peripheral.
  79. *
  80. * @return  none
  81. */
  82. void USART2_Init(void) {
  83.     GPIO_InitTypeDef  GPIO_InitStructure = {0};
  84.     USART_InitTypeDef USART_InitStructure = {0};
  85.     NVIC_InitTypeDef  NVIC_InitStructure = {0};

  86.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  87.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  88.     /* USART2 TX-->A.2   RX-->A.3 */
  89.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  90.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  91.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  92.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  93.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  94.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  95.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  96.     USART_InitStructure.USART_BaudRate = 115200;
  97.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  98.     USART_InitStructure.USART_StopBits = USART_StopBits_1;
  99.     USART_InitStructure.USART_Parity = USART_Parity_No;
  100.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  101.     USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

  102.     USART_Init(USART2, &USART_InitStructure);
  103.     #if USART_IDLE_RECV_MODE
  104.     USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
  105.     #else
  106.     USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
  107.     #endif
  108.     NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  109.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  110.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  111.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  112.     NVIC_Init(&NVIC_InitStructure);

  113.     USART_Cmd(USART2, ENABLE);
  114. }

  115. /*********************************************************************
  116. * @fn      DMA_INIT
  117. *
  118. * @brief   Configures the DMA for USART2 & USART3.
  119. *
  120. * @return  none
  121. */
  122. void DMA_INIT(void)
  123. {
  124.     DMA_InitTypeDef DMA_InitStructure = {0};
  125.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  126.     DMA_DeInit(DMA1_Channel7);
  127.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DATAR); /* USART2->DATAR:0x40004404 */
  128.     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_usart2TxBuf;
  129.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  130.     DMA_InitStructure.DMA_BufferSize = TX_BUF_SIZE;
  131.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  132.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  133.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  134.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  135.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  136.     DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  137.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  138.     DMA_Init(DMA1_Channel7, &DMA_InitStructure);

  139.     DMA_DeInit(DMA1_Channel6);
  140.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DATAR);
  141.     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_usart2RxBuf;
  142.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  143.     DMA_InitStructure.DMA_BufferSize = RX_BUF_SIZE;
  144.     DMA_Init(DMA1_Channel6, &DMA_InitStructure);
  145. }

  146. void USART2_Send_Data(uint8_t *data,uint16_t size) {
  147.     while(!g_usart2SendOK);
  148.     USART_SendData(USART2, *data++);
  149.     g_usart2SendOK = 0;
  150. }
  151. /*********************************************************************
  152. * @fn      USART2_IRQHandler
  153. *
  154. * @brief   This function handles USART2 global interrupt request.
  155. *
  156. * @return  none
  157. */
  158. void USART2_IRQHandler(void)
  159. {
  160.     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
  161.     {
  162.         USART_ClearFlag(USART2,USART_FLAG_RXNE);
  163.         if(g_usart2RxCnt > RX_BUF_SIZE) {
  164.             g_usart2RxCnt = 0;
  165.         } else {
  166.             g_rxTimeOut = 1;
  167.             g_usart2RxBuf[g_usart2RxCnt++] = USART_ReceiveData(USART2);
  168.         }
  169.     }
  170. }

  171. /*********************************************************************
  172. * @fn      SYSTICK_Init_Config
  173. *
  174. * @brief   SYSTICK_Init_Config.
  175. *
  176. * @return  none
  177. */
  178. void SYSTICK_Init_Config(u_int64_t ticks)
  179. {
  180.     SysTick->SR &= ~(1 << 0);//clear State flag
  181.     SysTick->CMP = ticks;
  182.     SysTick->CNT = 0;
  183.     SysTick->CTLR = 0xF;

  184.     NVIC_SetPriority(SysTicK_IRQn, 15);
  185.     NVIC_EnableIRQ(SysTicK_IRQn);
  186. }

  187. /*********************************************************************
  188. * @fn      SysTick_Handler
  189. *
  190. * @brief   SysTick_Handler.
  191. *
  192. * @return  none
  193. */
  194. void SysTick_Handler(void)
  195. {
  196.     if(SysTick->SR == 1)
  197.     {
  198.         SysTick->SR = 0;//clear State flag
  199.         if (g_rxTimeOut) {
  200.             g_rxTimeOut--;
  201.             if (!g_rxTimeOut)
  202.             {
  203.                 g_usart2RecvOK = 1; //一帧接收完成
  204.             }
  205.         }
  206.     }
  207. }
2、下载验证
1)串口助手设置100ms定时发送
685466880f7d13c5db.png
接收和发送都为59条数据
658956880f7e627ffe.png
2)串口助手设置5ms定时发送
波特率为115200 bit/s 以一个起始位、一个停止位计算 传输一个字节;
传输1个bit位需要 1/115200 = 8.6805us;
传输10bit = 86.805us; 那么两个字节之间的间隔为一个停止位和起始位
36个字节传输需要:86.805*36 = 3.125ms
再加上每次1ms的延时,以及printf的执行,会导致有些打印出来,因此只能搜索is来统计数据
201886880f7f38722e.png

556176880f7f9c0462.png

串口中断处理程序
630016880f805f10a8.png
综上:间隔100ms和间隔5ms发送和接收都是没有问题,可见CH32V307上手还是很快的,直接参考例程即可上手,快速开发。






您需要登录后才可以回帖 登录 | 注册

本版积分规则

11

主题

30

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部