CH32V30x和CH32V31x系列是基于青稞V4F微处理器设计的32位RISC-V内核MCU,工作频率144MHz,内置高速存储器,系统结构中多条总线同步工作,提供了丰富的外设功能和增强型 I/O 端口。内置 2 个 12 位 ADC 模块、2 个 12 位 DAC 模块、多组定时器、多通道触摸按键电容检测(TKey)等功能,还包含了标准和专用通讯接口:I2C、I2S、SPI、USART、SDIO、CAN 控制器、USB2.0 全速主机/设备控制器、USB2.0 高速主机/设备控制器(内置 480Mbps 收发器)、数字图像接口、千兆以太网控制器等。产品工作额定电压为 3.3V,工作温度范围为-40℃~85℃工业级。支持多种省电工作模式来满足产低功耗应用要求。系列产品中各型号在资源分配、外设数量、外设功能等方面有所差异,按需选择。
CH32V303/305/307 产品资源分配:307有8个串口,是8个,没错!!如果用STM32,上H7才可以。
用CH32V3**做串口服务器是理想选择,串口服务器是一种网络设备,想在将8个独立的TTL,RS-232、RS-485或RS-422串口设备连接到以太网,实现串口与网络之间的双向透明数据传输。其核心功能包括:
1,多串口支持:提供8个独立的串口接口,可同时连接多个串口设备。
2,协议转换:将串行数据封装为TCP/IP数据包进行传输,接收端还原为串行信号。
3,双向透明传输:确保数据在串口与网络之间无协议变化地传输,保持原始数据的完整性。
4,远程管理:支持通过Web界面、Telnet或专用配置工具进行远程参数设置和状态监控。
5,多协议支持:内部集成ARP、IP、TCP、UDP、HTTP、ICMP等协议,支持动态IP(DHCP)和静态IP配置。
灵活的工作模式:TCP Server模式:作为服务器端,等待客户端连接。
TCP Client模式:作为客户端,主动向服务器发起连接。
UDP模式:支持快速、低延迟的数据广播和接收。
虚拟串口模式:在计算机上创建虚拟串口,远程设备被识别为本地串口。
6,Modbus网关功能:支持Modbus TCP转Modbus RTU,实现上位机使用Modbus TCP协议对RS-485的Modbus RTU设备的数据采集。
7,多主机功能:支持多个计算机主站同时访问同一个串口设备,适用于一问一答的查询方式。
CH32V307/317串口特点:
多串口配置:CH32V307扩展了8组串口,包括3个通用同步异步收发器(USART1/2/3)和5个通用异步收发器(UART4/5/6/7/8),可同时连接多个串口设备,满足复杂系统需求。 高速通信能力:支持最高9Mbps的波特率传输,满足高速数据传输需求,适用于实时性要求高的应用场景。 灵活通信模式: - 全双工/半双工:支持同步或异步通信,适应不同协议要求。
- 同步模式:USART模块可输出时钟信号,通过CK引脚同步数据传输,适用于需要严格时序控制的场景。
- 异步模式:采用起始位、数据位、停止位和校验位的组合传输数据,无需同步时钟信号,实现简单灵活。
协议兼容性: - 支持LIN(局部互连网)、IrDA(红外数据协会)编码器、智能卡协议。
- 兼容调制解调器(CTS/RTS硬件流控)操作,满足多样化通信需求。
DMA支持:支持DMA操作连续通讯,减少CPU干预,提升数据传输效率,适用于大数据量场景。 中断功能:提供多种中断源,包括接收缓冲区非空中断(RXNE)和空闲线中断(IDLE),便于实时处理数据。空闲中断触发流程中,每接收到一个字节,RXNE标志置1,可通过检测IDLE标志实现帧接收。 低功耗设计:在保持高性能的同时,支持多种低功耗模式(睡眠、停止、待机),适用于电池供电或对功耗敏感的应用场景。 硬件加速:配备硬件堆栈区和快速中断入口,在标准RISC-V基础上提高中断响应速度,确保串口通信的实时性和可靠性。
先编写一个串口打印测试:
main.c
#include "debug.h"
// 简单延时函数(单位:微秒)
void Delay_us(uint32_t us) {
for (uint32_t i = 0; i < us; i++) {
for (volatile uint32_t j = 0; j < 7; j++); // 调整循环次数以适配你的时钟频率
}
}
// 简单延时函数(单位:毫秒)
void Delay_ms(uint32_t ms) {
for (uint32_t i = 0; i < ms; i++) {
for (volatile uint32_t j = 0; j < 7200; j++); // 调整循环次数以适配你的时钟频率
}
}
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() );
printf("This is printf example\r\n");
while(1)
{
printf("SystemClk:%d\r\n",SystemCoreClock);
printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
printf("This is printf example\r\n");
Delay_ms(1000);
}
}
#include "debug.h"
static uint8_t p_us = 0;
static uint16_t p_ms = 0;
#define DEBUG_DATA0_ADDRESS ((volatile uint32_t*)0xE0000380)
#define DEBUG_DATA1_ADDRESS ((volatile uint32_t*)0xE0000384)
/*********************************************************************
* @fn Delay_Init
*
* [url=home.php?mod=space&uid=247401]@brief[/url] Initializes Delay Funcation.
*
* [url=home.php?mod=space&uid=266161]@return[/url] none
*/
void Delay_Init(void)
{
p_us = SystemCoreClock / 8000000;
p_ms = (uint16_t)p_us * 1000;
}
/*********************************************************************
* @fn Delay_Us
*
* @brief Microsecond Delay Time.
*
* @param n - Microsecond number.
*
* @return None
*/
void Delay_Us(uint32_t n)
{
uint32_t i;
SysTick->SR &= ~(1 << 0);
i = (uint32_t)n * p_us;
SysTick->CMP = i;
SysTick->CTLR |= (1 << 4);
SysTick->CTLR |= (1 << 5) | (1 << 0);
while((SysTick->SR & (1 << 0)) != (1 << 0))
;
SysTick->CTLR &= ~(1 << 0);
}
/*********************************************************************
* @fn Delay_Ms
*
* @brief Millisecond Delay Time.
*
* @param n - Millisecond number.
*
* @return None
*/
void Delay_Ms(uint32_t n)
{
uint32_t i;
SysTick->SR &= ~(1 << 0);
i = (uint32_t)n * p_ms;
SysTick->CMP = i;
SysTick->CTLR |= (1 << 4);
SysTick->CTLR |= (1 << 5) | (1 << 0);
while((SysTick->SR & (1 << 0)) != (1 << 0))
;
SysTick->CTLR &= ~(1 << 0);
}
/*********************************************************************
* @fn USART_Printf_Init
*
* @brief Initializes the USARTx peripheral.
*
* @param baudrate - USART communication baud rate.
*
* @return None
*/
void USART_Printf_Init(uint32_t baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
#if(DEBUG == DEBUG_UART1)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
#elif(DEBUG == DEBUG_UART2)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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);
#elif(DEBUG == DEBUG_UART3)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
#endif
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_Tx;
#if(DEBUG == DEBUG_UART1)
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
#elif(DEBUG == DEBUG_UART2)
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
#elif(DEBUG == DEBUG_UART3)
USART_Init(USART3, &USART_InitStructure);
USART_Cmd(USART3, ENABLE);
#endif
}
/*********************************************************************
* @fn SDI_Printf_Enable
*
* @brief Initializes the SDI printf Function.
*
* @param None
*
* @return None
*/
void SDI_Printf_Enable(void)
{
*(DEBUG_DATA0_ADDRESS) = 0;
Delay_Init();
Delay_Ms(1);
}
/*********************************************************************
* @fn _write
*
* @brief Support Printf Function
*
* @param *buf - UART send Data.
* size - Data length
*
* @return size: Data length
*/
__attribute__((used)) int _write(int fd, char *buf, int size)
{
int i = 0;
#if (SDI_PRINT == SDI_PR_OPEN)
int writeSize = size;
do
{
/**
* data0 data1 8 bytes
* data0 The lowest byte storage length, the maximum is 7
*
*/
while( (*(DEBUG_DATA0_ADDRESS) != 0u))
{
}
if(writeSize>7)
{
*(DEBUG_DATA1_ADDRESS) = (*(buf+i+3)) | (*(buf+i+4)<<8) | (*(buf+i+5)<<16) | (*(buf+i+6)<<24);
*(DEBUG_DATA0_ADDRESS) = (7u) | (*(buf+i)<<8) | (*(buf+i+1)<<16) | (*(buf+i+2)<<24);
i += 7;
writeSize -= 7;
}
else
{
*(DEBUG_DATA1_ADDRESS) = (*(buf+i+3)) | (*(buf+i+4)<<8) | (*(buf+i+5)<<16) | (*(buf+i+6)<<24);
*(DEBUG_DATA0_ADDRESS) = (writeSize) | (*(buf+i)<<8) | (*(buf+i+1)<<16) | (*(buf+i+2)<<24);
writeSize = 0;
}
} while (writeSize);
#else
for(i = 0; i < size; i++)
{
#if(DEBUG == DEBUG_UART1)
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData(USART1, *buf++);
#elif(DEBUG == DEBUG_UART2)
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
USART_SendData(USART2, *buf++);
#elif(DEBUG == DEBUG_UART3)
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
USART_SendData(USART3, *buf++);
#endif
}
#endif
return size;
}
/*********************************************************************
* @fn _sbrk
*
* @brief Change the spatial position of data segment.
*
* @return size: Data length
*/
__attribute__((used)) void *_sbrk(ptrdiff_t incr)
{
extern char _end[];
extern char _heap_end[];
static char *curbrk = _end;
if ((curbrk + incr < _end) || (curbrk + incr > _heap_end))
return NULL - 1;
curbrk += incr;
return curbrk - incr;
}
测试结果:nice!!
SystemClk:96000000
ChipID:3173b568
This is printf example
SystemClk:96000000
ChipID:3173b568
This is printf example
SystemClk:96000000
ChipID:3173b568
This is printf example
SystemClk:96000000
ChipID:3173b568
This is printf example
SystemClk:96000000
ChipID:3173b568
This is printf example
SystemClk:96000000
ChipID:3173b568
This is printf example
SystemClk:96000000
ChipID:3173b568
This is printf example
|