- 2021-03-01
-
发表了主题帖:
【RISC-V MCU CH32V103测评】+ TIM定时器的使用
CH32V103有7个定时器,
1个16位高级定时器,包含通用定时器功能,并自带死区控制和紧急刹车,提供用于电机控制的PWM,
3个16位通用定时器,提供多达4个用于输入捕获/输出比较/PWM/脉冲计数的通道和增量编码器输入,
2个看门狗定时器(独立和窗口型),
系统时间定时器:64位自增型计数器.
我手中的DHT11温湿度传感器要一秒以上才能读取一次,所以就要用一个定时器来定时1.3秒读取一次,详细配置如下:
/*
* TIM2用作DHT11更新时基
* 1.3秒更新一次
*/
void TIM2_Base_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE );
TIM_TimeBaseInitStructure.TIM_Period = 13000-1;//计数值
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200-1;//分频值
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);//配置更新中断
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
配置起来不难和ST差不多,不同点在中断控制器上.对比如下:
CH32V103C8T6,沁恒微电子的RSIC-V架构32位通用型MCU,支持IMAC指令集,内置快速可编程中断控制器(PFIC– Programmable Fast Interrupt Controller)。PFIC是该公司自研设计的结构,所以用法上有独自的特色。
PFIC 控制器
44+3个可单独屏蔽中断,每个中断请求都有独立的触发和屏蔽位、状态位
提供一个不可屏蔽中断NMI
2级嵌套中断进入和退出硬件自动压栈和恢复,无需指令开销
4路可编程快速中断通道,自定义中断向量地址
CH32V103C8T6在中断写法上,书写一个中断服务函数时,需要为其声明中断属性,即在函数名前添加__attribute__((interrupt())),这样IDE在进行编译时,会将此函数体识别为中断服务函数,主动添加“压栈出栈”处理及中断返回指令。例如:在ch32v10x_it.c的顶部有如下写法.
void NMI_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void HardFault_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void EXTI0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void TIM2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
中断服务函数中只要置位即可,处理交给while.
/*******************************************************************************
* Function Name : TIM2_IRQHandler
* Description : This function handles TIM2 Handler.
* Input : None
* Return : None
*******************************************************************************/
void TIM2_IRQHandler(void)
{
if(TIM_GetFlagStatus(TIM2, TIM_IT_Update)!= RESET){
DHT11_Updata = 1;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
然后主程序去处理就好了
/*******************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Return : None
*******************************************************************************/
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n",SystemCoreClock);
//初始化
GPIO_Toggle_INIT();
EXTI0_INT_INIT();
SPI1_Init();
DHT11_Init();
ADC_Function_Init();
DMA_Tx_Init();
OLED_Init();
TIM2_Base_Init();
Opening_page();//启动页
OLED_Clear();
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //启动ADC转换
TIM_Cmd(TIM2,ENABLE); //使能定时器,1.3秒中断一次
while(1)
{
// GPIO_WriteBit(GPIOA, GPIO_Pin_0, (i==0) ? (i=Bit_SET):(i=Bit_RESET));
if(exti0_status == 0) //光敏电阻感到光
{
OLED_DisPlay_On(); //开启OLED
TIM_Cmd(TIM2,ENABLE);
if(DHT11_Updata == 1)
{ /*调用DHT11_Read_TempAndHumidity读取温湿度,若成功则输出该信息*/
if( DHT11_Read_TempAndHumidity ( & DHT11_Data ) == SUCCESS)
{
Main_page(); //成功显示温湿度,ADC电压值
}else
{
OLED_Clear();
DHT_ERR(); //失败显示错误
}
DHT11_Updata = 0;
}
MQ_7_Vol();
}else
{
OLED_DisPlay_Off(); //关闭oled
TIM_Cmd(TIM2,DISABLE); //关闭定时器
}
Delay_Ms(150);
}
}
这里TIM2只是用作了DHT11更新时基,其他神马和ST差不多,唯一不同点便是这中断的写法了.
- 2021-02-21
-
发表了主题帖:
【RISC-V MCU CH32V103测评】+ EXTI中断输入开关OLED
上次驱动OLED屏之后一天晚上在想,这屏要是晚上也亮着不就小夜灯了(晚上有光睡不着). 所以这次加个光敏电阻模块让他白天显示,晚上就关掉屏.光敏电阻模块经LM393后输出高低电平,触发中断输入,然后读取中断脚PA0引脚电平后置变量exti0_status 0或1.主要处理在while里处理.
/*******************************************************************************
* Function Name : EXTI0_INT_INIT
* Description : Initializes EXTI0 collection.
* Input : None
* Return : None
*******************************************************************************/
void EXTI0_INT_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA,ENABLE);//开启时钟
//设定引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设为浮动输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//中断参数设置
/* GPIOA ----> EXTI_Line0 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//上升下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
//优先级设置
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
先初始化一下引脚,中断模式,中断优先级.
然后是中断响应
/*******************************************************************************
* Function Name : EXTI0_IRQHandler
* Description : This function handles EXTI0 Handler.
* Input : None
* Return : None
*******************************************************************************/
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
{
//根据引脚电平设置exti0_status变量值
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_SET)
{
exti0_status = 1;
}else
{
exti0_status = 0;
}
EXTI_ClearITPendingBit(EXTI_Line0); /* 清除标志 */
}
}
main中编写代码如下
while(1)
{
if(exti0_status == 0)
{
OLED_DisPlay_On(); //开启OLED
uint16_t Vrl = 3.3f * ADC_Value / 4095.f;
uint16_t Vrl_t = ((3.3f * ADC_Value / 4095.f)*1000-Vrl);
OLED_ShowNum(48,16,Vrl,1,24);
OLED_ShowChar(62,16,'.',24);//.
OLED_ShowNum(74,16,Vrl_t,3,24);
OLED_Refresh();
Delay_Ms(50);
}else
{
OLED_DisPlay_Off(); //关闭OLED
}
}
烧录进去后可以看到图一开灯OLED亮起,图二关灯OLED关闭.
夜深了,追剧去了.....
- 2021-02-15
-
回复了主题帖:
STM32MP157A-DK1测评 - 1、开箱、开发板和SOC等
官方有公开原理图和物料清单的,那个料是wifi&BLE一体的,有风枪可以自己吹上去,
-
发表了主题帖:
【RISC-V MCU CH32V103测评】+ DMA传输ADC转换结果
先祝大家新年快乐,新的一年里,划水不被捉,牛码不Bug,电脑不卡机,下班不漏卡.
这次使用ADC采集结果并使用DMA传输结果(有小弟当然要他搬砖了).最后OLED显示出来,还是上回的GPIO例程接着改,有关ADC的配置参数可以参考官方文档配置ADC配置教程和DMA配置例程,里面有每个函数的使用说明,DMA例程是储存器到储存器的,改一下就可以了.其详细初始化代码如下:
/*******************************************************************************
* Function Name : ADC_Function_Init
* Description : Initializes ADC collection.
* Input : None
* Return : None
*******************************************************************************/
void ADC_Function_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE );
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE); // ADC DMA 使能
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
/*******************************************************************************
* Function Name : DMA_Tx_Init
* Description : Initializes the DMAy Channelx configuration.
* Input : DMA_CHx:
* x can be 1 to 7.
* ppadr: Peripheral base address.
* memadr: Memory base address.
* bufsize: DMA channel buffer size.
* Return : None
*******************************************************************************/
void DMA_Tx_Init(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->RDATAR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_Value;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure );
DMA_Cmd(DMA1_Channel1, ENABLE);
}
main.c中声明一个全局变量__IO uint16_t ADC_Value;用来储存ADC的转换结果,ADC转换后会请求DMA传输到变量ADC_Value中.
由于转换为电压之后的结果是小数所以这里拆成两个整数 给OLED来显示,
uint16_t Vrl = 3.3f * ADC_Value / 4095.f;
uint16_t Vrl_t = ((3.3f * ADC_Value / 4095.f)*1000-Vrl);
可以看到电压结果已经输出了.第一张接VCC电压,第二张接MQ传感器电压.
值得一提的是如果采用5伏供电,那么ADC的电压范围就是0-5伏了,这点非常好.
http://home.eeworld.com.cn/forum.php?mod=attachment&aid=NTI1MDYzfDFmMjU3NjMwMTg0NTA0NWI2OTJiZDYyZmQ0MTMyZTE5fDE2MTQ4MTM2ODY%3D&request=yes&_f=.7z
- 2021-02-08
-
发表了主题帖:
【RISC-V MCU CH32V103测评】+ 硬件SPI驱动OLED显示DHT11温湿度
上回驱动了个DHT11,并用串口输出温湿度,为了接下来便于显示传感器信息,添加了一块0.96寸OLED屏来显示,还是上次的GPIO项目,新建个SPI.c然后从官方SPI例程中拷贝初始化代码,如下,之前一直调不通,但换其他片子能驱动,一时不得姐,最后修改分频器为2分频竟然跑起来了,同样都是72M,ST在8分频下依旧可以跑,但在沁恒上却只能2分频,以后再研究了,切正题.
OLED用的SSD1306,中景园的屏,例程是模拟SPI,这里把他改为硬件SPI,如下:
然后while里添加显示信息,
打完收工,话时没有main.h头文件用起来还真有些不太顺手,
效果还可以.
GPIO_Toggle.7z
-
回复了主题帖:
【RISC-V MCU CH32V103测评】SPI的测试
哥们我刚调通,这个成员SPI_BaudRatePrescaler要2分频才驱动起来,具体原因以后再研究了,
-
回复了主题帖:
CH32V103的SPI有跑通的吗?
我也是用硬件spi驱不起来,想debug下也报端口错误,你解决没
- 2021-01-30
-
回复了主题帖:
蓝牙、NFC 24小时开启耗电吗?
确实,NFC在解锁屏的情况下只是间歇检测磁场工作,不费啥电,反倒是屏和移动网络才是耗电大户
-
发表了主题帖:
【RISC-V MCU CH32V103测评】+ 读取DH11
上回用例程点了个灯了解了一下就一直吃灰了,这周末有了时间就继续耍,这次驱动个DHT11,依旧用上次的Toggle例程修改下接着用,新建DHT11文件夹,再新建一个DHT11.c和.h.->>参考新建工程步骤 .然后直接找个例程代码拷进去(请叫我CV大师),先修改下.h中的宏定义,再改.c中的gpio配置函数,如下,然后while里添加打印代码.
烧录选项里叉掉Erase ALL(比较费时间),烧录进去,打开串口,可以看到打印信息,然后中文和符号乱码了,串口配置UTF-8也不行,配置GBK可以打印中文但后面怎么没了,擦,还是用串口助手把!哈,正常了.
有搞懂的朋友指点下哦.
工程在这,GPIO_Toggle.7z
Bye........
- 2021-01-24
-
发表了主题帖:
【RISC-V MCU CH32V103测评】+首次使用
首先感谢EEWORD论坛的这次评测活动,有幸能够评测沁恒电子CH32V103这颗片子,看官方资料这是一颗基于开源的RISC_V内核的微控制器,至于沁恒想必没几个人没用过他家CH340USB转串口芯片吧,话不多说先来几张图,
图1.2是沁恒的link,采用自家CH549G做的,使用SWD调试接口还带了一个串口,调试起来看Log还是挺方便的.
图3.4是CH32V103C8T6(这命名有点....)为主控的板子了,板载了一个Type_C口,一个A母口,80M主频,这颗片子是支持2.7V到5.5V的,电池供电场合可以省掉俩电容和LDO了,(来自老板肯定的眼神).
相关资料可以在这里下到->>沁恒微电子资料下载,沁恒还提供了IDE,
对比STM32F103C8T6看了下寄存器映射表高度一致,引脚定义完全兼容,这货就是来肛STM32F103的.因为基于开源内核,所以不会受到政交的影响.
沁恒IDE,MuonRiver Studio是基于Eclipse做的,安装过程一路Next.官方在文库做了个教程文档,->>沁恒教程文档.开个官方GPIO的例程看下先,
借用下野火的例程(左边),沁恒的在右边,另外对比了下驱动库也是惊人的高度吻合,简直就是异父异母的孪生兄弟,几乎可以无缝从STM32F103过渡到CH32V103.入手第一步先点灯.
把SWD杜邦线接好,串口TX(PA9)接到Link上.LED灯是引出的插针并未直接GPIO所以要杜邦线连接PA0和LED1.启动MuonRiver Studio,插上Link,
1编译,2配置,3下载,4配置串口.可以看到LED在闪烁,复位下可以看到打印信息.
IDE内加入串口调试窗口和LINK上加个串口确实很方便查看打印信息的.
未完待续..........
- 2021-01-18
-
回复了主题帖:
测评入围名单:沁恒RISC-V架构32位通用MCU CH32V103有奖评测
个人信息无误,确认可以完成评测计划