一. 沁恒微电子
南京沁恒微电子股份有限公司是一家高速数模混合公司主要产品集成电路设计公司,成立于2004年,公司位于江苏南京。公司主要在物联网领域专注于连接和控制方面的芯片设计以及应用技术开发。
沁恒微电子于2020年2月24日发布了首款基于 RISC-V架构,自主设计的RISC-V3A处理器内核及 其硬件产品—— CH32V103系列MCU。
二. CH32V103系列MCU
1.芯片简介
CH32V103 系列是以RISC-V3A处理器为核心的32位通用微控制器,该处理器是基于RISC-V开源指令集设计。片上集成了时钟安全机制、多级电源管理、通用DMA控制器。此系列具有1路USB2.0主机/设备接口、多通道12位ADC转换模块、多通道触摸按键电容检测、多组定时器、多路I2C/USART/SPI接口等丰富的外设资源。
2. CH32V103x 产品型号说明
1)芯片系列:CH32 代表的是沁恒微电子品牌的 32 位 MCU 2)芯片类型:V – RISC-V 内核,F – Cortex-M3 系列内核 3)芯片子系列:103 – 增强型 4)引脚数目:T – 36 脚,C – 48 脚,R – 64 脚,V – 100 脚,Z – 144 脚 5)Flash 容量:6 – 32K 字节 Flash,8 – 64K 字节 Flash,B – 128K 字节 Flash,C – 256K字节 Flash 6)封装信息:H – BGA 封装,T – LQFP 封装,U – VFQFPN 封装,Y – WLCSP/ WLCSP64 7)工作温度范围:6 – -40 ~ 85℃(工业级),7 – -40 ~ 105℃(工业级)
3. CH32V103x 产品型号对比
4.产品内部架构框图
5. 时钟树框图
三. 沁恒 CH32V103R8T6 MCU
1. 产品特性
内核: ----32位RISC-V内核 ----最高主频80MHz ----单周期乘法和硬件除法
低功耗: 多种低功耗模式(睡眠/停止/待机)
系统时钟: ----内嵌8MHz的RC振荡器 ----内嵌40KHz的RC振荡器 ----内嵌锁相环,最高120MHz ----外部支持32768Hz低速振荡器
存储器: 20KB易失数据存储区SRAM 64KB用户应用程序存储区CodeFlash
2. 外设模块
DMA控制器: ----7通道,支持环形缓冲区管理 ----支持多外设
定时器: 1个实时时钟 1个高级定时器 1个滴答定时器 2个看门狗定时器 3个通用定时器
ADC: 1个12位逐次逼近型ADC 支持16个外部通道和2个内部通道
UASRT: 3个通用同步异步收发器,最高支持4.5Mbps
SPI: 2个串行外设接口,支持主、从、多从模式
USB2.0全速: 1个USB全速主机/设备控制器,支持USB2.0全速 12Mbps或低速1.5Mbps
3. 应用案例
点灯测试是每一款MCU的必经之路,这里采用呼吸灯作为演示。
3.1 GPIO初始化
注意: 由于演示程序采用呼吸灯,即通过改变LED对应IO的PWM占空比控制小灯亮灭程度,所以需要初始化具有PWM输出功能的引脚。
void GPIO_init(PWMCH_enum pwmch, uint32 freq, uint32 duty)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16 match_temp;
uint16 period_temp;
uint16 freq_div = 0;
pwm_gpio_init(pwmch);
if((pwmch >> 8) == 0x00)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
else if((pwmch >> 8) == 0x01)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
else if((pwmch >> 8) == 0x02)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
else if((pwmch >> 8) == 0x03)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
if((pwmch >> 4) == 0x10)
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM1, ENABLE);
else if((pwmch >> 4) == 0x11)
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);
else if((pwmch >> 4) == 0x21)
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);
else if((pwmch >> 4) == 0x22)
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
sys_clk = 8000000 * (((RCC->CFGR0 >> 18)&0x0F) + 2);
freq_div = (uint16)((sys_clk / freq) >> 16);
period_temp = (uint16)(sys_clk/(freq*(freq_div + 1)));
match_temp = period_temp * duty / PWM_DUTY_MAX;
TIM_TimeBaseStructure.TIM_Period = period_temp - 1;
TIM_TimeBaseStructure.TIM_Prescaler = freq_div;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputState_Disable;
TIM_OCInitStructure.TIM_Pulse = match_temp;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_TimeBaseInit(((TIM_TypeDef *) TIMERN[pwmch>>8]), &TIM_TimeBaseStructure);
if((pwmch & 0x03) == 0x00)
{
TIM_OC1Init(((TIM_TypeDef *) TIMERN[pwmch>>8]), &TIM_OCInitStructure );
TIM_OC1PreloadConfig(((TIM_TypeDef *) TIMERN[pwmch>>8]), TIM_OCPreload_Enable);
TIM_OC1FastConfig(((TIM_TypeDef *) TIMERN[pwmch>>8]), TIM_OC1FE);
}
else if((pwmch & 0x03) == 0x01)
{
TIM_OC2Init(((TIM_TypeDef *) TIMERN[pwmch>>8]), &TIM_OCInitStructure );
TIM_OC2PreloadConfig(((TIM_TypeDef *) TIMERN[pwmch>>8]), TIM_OCPreload_Enable);
TIM_OC2FastConfig(((TIM_TypeDef *) TIMERN[pwmch>>8]), TIM_OC2FE);
}
else if((pwmch & 0x03) == 0x02)
{
TIM_OC3Init(((TIM_TypeDef *) TIMERN[pwmch>>8]), &TIM_OCInitStructure );
TIM_OC3PreloadConfig(((TIM_TypeDef *) TIMERN[pwmch>>8]), TIM_OCPreload_Enable);
TIM_OC3FastConfig(((TIM_TypeDef *) TIMERN[pwmch>>8]), TIM_OC3FE);
}
else if((pwmch & 0x03) == 0x03)
{
TIM_OC4Init(((TIM_TypeDef *) TIMERN[pwmch>>8]), &TIM_OCInitStructure );
TIM_OC4PreloadConfig(((TIM_TypeDef *) TIMERN[pwmch>>8]), TIM_OCPreload_Enable);
TIM_OC4FastConfig(((TIM_TypeDef *) TIMERN[pwmch>>8]), TIM_OC4FE);
}
TIM_Cmd(((TIM_TypeDef *) TIMERN[pwmch>>8]), ENABLE);
TIM_CtrlPWMOutputs(((TIM_TypeDef *) TIMERN[pwmch>>8]), ENABLE );
}
3.2 逻辑功能介绍
呼吸灯实现亮灭变化的效果,在程序上就是PWM的成比例增加或减少。
在演示程序中,设置满占空比为10000,PWM频率为100,引脚占空比初值为10000,每次自减量为100。
pwm_init(PWM4_CH3_B8,100,10000);
pwm_init(PWM4_CH4_B9,100,10000);
while(1)
{
systick_delay_ms(15);
if(T1 == 0)
{
T-=100;
if(T == 0)
T1 = 1;
}
else
{
T+=100;
if(T == 10000)
{
T1 = 0;
}
}
pwm_duty(PWM4_CH3_B8, 10000-T);
pwm_duty(PWM4_CH4_B9, T);
}
3.3 演示视频
由于评估板板载LED未连接引脚,这里使用杜邦线将具有PWM输出功能的PB8,PB9与LED端口连接。
呼吸灯演示视频
从视频中可以看到,两颗LED灯循环实现呼吸效果。
3.4 示例程序
演示程序已经打包上传,但是一直在审核,审核通过后会将链接发在评论区。
|