- 2021-03-01
-
回复了主题帖:
【RISC-V MCU CH32V103测评】W25Q16读写及应用
peter91688 发表于 2021-2-28 22:09
很有实用价值哦,感谢感谢
- 2021-02-28
-
回复了主题帖:
【RISC-V MCU CH32V103测评】W25Q16读写及应用
Jacktang 发表于 2021-2-28 10:35
看来外挂的外挂的W25Q16也照样用
没错!
-
发表了主题帖:
【RISC-V MCU CH32V103测评】W25Q16读写及应用
在老版的CH32V103开发板上带有W25Q16存储器,可存放图库和字库等相对固定的数据内容。而在新版的开发板上,该器件被去除了,但我们不妨为它配上一个外挂的W25Q16模块来使用。
模块的接口电路如图1所示:
图1 模块接口电路
在老版的开发板上,W25Q16的读写电路如图2所示,为此我们可以为片选引脚CS添加一个10K的上拉电阻。
图2 板上W25Q16读写电路
外挂模块与开发板的连接形式如图3所示:
图3 外挂模块连接
具体的引脚连接关系为:
CS —— PA2
DO —— PA6(SPI1_MISO)
WP —— 3.3V
DI —— PA7(SPI1_MOSI)
CLK —— PA5(SPI1_SCK)
HOLD —— 3.3V
测试程序可直接使用厂家提供的例程,其主程序如下:
int main(void)
{
u8 datap[SIZE];
u16 Flash_Model;
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n",SystemCoreClock);
SPI_Flash_Init();
Flash_Model = SPI_Flash_ReadID();
switch(Flash_Model)
{
case W25Q80:
printf("W25Q80 OK!\r\n");
break;
case W25Q16:
printf("W25Q16 OK!\r\n");
break;
case W25Q32:
printf("W25Q32 OK!\r\n");
break;
case W25Q64:
printf("W25Q64 OK!\r\n");
break;
case W25Q128:
printf("W25Q128 OK!\r\n");
break;
default:
printf("Fail!\r\n");
break;
}
printf("Start Erase W25Qxx....\r\n");
SPI_Flash_Erase_Sector(0);
printf("W25Qxx Erase Finished!\r\n");
Delay_Ms(500);
printf("Start Read W25Qxx....\r\n");
SPI_Flash_Read(datap,0x0,SIZE);
printf("%s\r\n", datap );
Delay_Ms(500);
printf("Start Write W25Qxx....\r\n");
SPI_Flash_Write((u8*)TEXT_Buf,0,SIZE);
printf("W25Qxx Write Finished!\r\n");
Delay_Ms(500);
printf("Start Read W25Qxx....\r\n");
SPI_Flash_Read(datap,0x0,SIZE);
printf("%s\r\n", datap );
while(1);
}
有程序可以看出,它不但对W25Q16有效,而且几乎对整个W25Q效率都是有效的。
经读写验证,其效果如图4所示,说明验证成功。有了这个基础,我们就可以为开发板构建一个自己的字库了。
图4 读写效果
- 2021-02-26
-
回复了主题帖:
开工大吉,抢楼有礼!预测:2021年电子热门关键词
在嵌入式MCU上跑AI应用应该会更加流行
-
回复了主题帖:
开工大吉,抢楼有礼!预测:2021年电子热门关键词
汽车应用的雷达毫米波技术
-
回复了主题帖:
【RISC-V MCU CH32V103测评】UART串行通讯
freebsder 发表于 2021-2-25 22:30
串口的设置应该都是一样的吧,抄来改改就好了。
但必须去实践和测试!
- 2021-02-21
-
发表了主题帖:
【RISC-V MCU CH32V103测评】UART串行通讯
CH32V103有3个串口,分别是USART1、USART2及USART3,所占用的引脚如下:
USART1 TX-->A.9 RX-->A.10
USART2 TX-->A.2 RX-->A.3
USART3 TX-->B.10 RX-->B.11
在通常的情况下,USART1作调试信息输出口,其它2个串口作通讯功能用。
此外,在使用过程它又分为以查询方式接受和以中断方式接收。
最近在一个朋友的项目中要用到3个串行口,且需要以中断方式进行接收,为此打算以CH32V103来解决它。
作为中断方式接收在例程中有使用2个串口的示例,因此关键的是解决第3个串口的中断接收问题,也就是解决USART1中断接收的问题。
经过努力,该问题得到了较好地解决,其测试连接和效果如图1至图3所示。
图1 测试线路连接
图2 双串口通信测试
图3 UART1中断接收测试
3个串口的中断接收初始化函数为:
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
}
3个串口的中断接收引脚配置化函数为:
void USARTx_CFG(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2|RCC_APB1Periph_USART3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB , ENABLE);
/* USART1 TX-->A.9 RX-->A.10 */
//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);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 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);
/* USART3 TX-->B.10 RX-->B.11 */
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);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &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(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Init(USART3, &USART_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
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);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
USART_Cmd(USART2, ENABLE);
USART_Cmd(USART3, ENABLE);
}
主程序的内容为:
int main(void)
{
uint8_t i;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
USART_Printf_Init(115200);//115200
printf("SystemClk:%d\r\n",SystemCoreClock);
printf("USART Interrupt TEST! \r\n");
USARTx_CFG();
Rxfinish0=0;
while(1)
{
if(Rxfinish0==1)
{
Rxfinish0=0;
TxCnt0=0;
while(TxCnt0<10)
{
USART_SendData(USART1, RxBuffer0[TxCnt0++]);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
RxCnt0=0;
//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}
}
}
- 2021-02-18
-
回复了主题帖:
【RISC-V MCU CH32V103测评】BH1750光强检测
w494143467 发表于 2021-2-17 14:51
感谢分享,期待后续的测评计划帖子哈,我也会持续关注你的哈!!!
- 2021-02-15
-
回复了主题帖:
【RISC-V MCU CH32V103测评】BH1750光强检测
本帖最后由 jennyzhaojie 于 2021-2-15 10:20 编辑
bigbat 发表于 2021-2-15 08:51 为啥非要使用IO口来模拟IIC,硬件上不是有IIC吗?这种用法在任务少的时候没有问题,但是在多任务的环境下这 ...
主要是易于移植,使用引脚不受限制;对于容量大的好上系统,小的会受限些。
-
发表了主题帖:
【RISC-V MCU CH32V103测评】BH1750光强检测
BH1750是一款数字式光强度传感器,相较于光敏电阻与A/D转换器所构成的光强检测,基于使用简便无需进行标度处理等特点。
BH1750是采用I2C接口来工作的,在使用时,可通过2个I/O口来模拟I2C通讯来进行环境光的检测。
BH1750与开发板的连接及显示效果如下图所示:
在模拟I2C通讯的过程中,对其输出高低电平及读取输入信号的相关定义如下:
#define SCL_Set() GPIO_WriteBit(GPIOA, GPIO_Pin_11, Bit_SET)
#define SCL_Clr() GPIO_WriteBit(GPIOA, GPIO_Pin_11, Bit_RESET)
#define SDA_Set() GPIO_WriteBit(GPIOA, GPIO_Pin_12, Bit_SET)
#define SDA_Clr() GPIO_WriteBit(GPIOA, GPIO_Pin_12, Bit_RESET)
配置BH1750相关引脚的初始化函数为:
void BH1750_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO_InitTypeDef类型的结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能与LED相关的GPIO端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12; //配置GPIO引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置GPIO模式为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; //设置GPIO口输出速度 GPIO_Speed_50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //调用库函数,初始化GPIOA
}
将相关引脚设置为输入功能的函数为:
void IIC_INPUT_MODE_SET()
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO_InitTypeDef类型的结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能与LED相关的GPIO端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //配置GPIO引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置GPIO模式为输入 GPIO_Mode_IPD GPIO_Mode_IPU
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_10MHz ; //设置GPIO口输出速度 GPIO_Speed_50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //调用库函数,初始化GPIOA
}
将相关引脚设置为输出功能的函数为:
void IIC_OUTPUT_MODE_SET()
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO_InitTypeDef类型的结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能与LED相关的GPIO端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //配置GPIO引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置GPIO模式为推挽输出
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_10MHz ; //设置GPIO口输出速度GPIO_Speed_50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //调用库函数,初始化GPIOA
}
BH1750的多字节读取函数为:
void Multiple_Read_BH1750()
{
BH1750_Start();
BH1750_SendByte(SlaveAddress+1);
BH1750_RecvACK();
BUF[0] = BH1750_RecvByte();
BH1750_SendACK(0);
BUF[1] = BH1750_RecvByte();
BH1750_SendACK(1);
BH1750_Stop();
Delay_Ms(5);
}
读取光强度值得函数为:
void Get_Sunlight_Value()
{
int dis_data=0;
float temp;
char i=0;
int sd;
Single_Write_BH1750(0x01); // power on
Single_Write_BH1750(0x10); // H- resolution mode
Delay_Ms(180);
Multiple_Read_BH1750();
for(i=0;i<3;i++) dis_data=BUF[0];
dis_data=(dis_data<<8)+BUF[1];
temp=(float)dis_data/1.2;
sd=(int)temp;
if(sd<54612) OLED_ShowNum(0,2,sd,5,16);
}
实现显示效果的主程序为:
int main(void)
{
uint8_t senflag;
Delay_Init(); //延时函数初始化
app_OLED_Init();
OLED_Init();
OLED_Clear();
OLED_ShowString(0,0,"CH32V103 TEST",16);
OLED_ShowString(0,2,"OLED & BH1750",16);
BH1750_Init();
Delay_Ms(2000);
OLED_Clear();
OLED_ShowString(0,0,"Sunlight=",16);
OLED_ShowString(48,2,"lx",16);
while(1)
{
Get_Sunlight_Value();
Delay_Ms(500);
}
}
- 2021-02-09
-
发表了主题帖:
【RISC-V MCU CH32V103测评】DHT22温湿度测量
本帖最后由 jennyzhaojie 于 2021-2-9 17:47 编辑
DHT22是一款数字式温湿度传感器,相较于热敏式的传感器具有无需A/D转换器参与、无需进行线性化处理等优势。
DHT22采用的是一种单总线式的结构,由此只需一个I/O口就可模拟工作方式来检测环境的温湿度变化。
DHT22与开发板的连接及显示效果如下图所示:
DHT22连接及检测效果图
由于DHT22是以单总线进行工作,故对其输出高低电平及读取输入信号的引脚定义如下:
#define DHT22_D0_H GPIOB->BSHR = GPIO_Pin_4
#define DHT22_D0_L GPIOB->BCR = GPIO_Pin_4
#define DHT22_D0_R GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4)
因DHT22在工作时,要在输入与输出模式间切换,故所用的引脚输入和输出模式配置函数如下:
void DHT22_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_10MHz ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void DHT22_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_10MHz ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
对DHT22进行数据读取的函数为:
uint8_t DHT22_Read_Data(uint8_t *temp,uint8_t *humi)
{
uint8_t buf[5];
uint8_t i;
DHT22_Rst();
if(DHT22_Check()==0)
{
for(i=0;i<5;i++)
{
buf=DHT22_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humi=(buf[0]*256+buf[1])/10;
*temp=(buf[2]*256+buf[3])/10;
}
}else return 1;
return 0;
}
对DHT22所用引脚PB4进行初始化的函数为:
uint8_t DHT22_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
DHT22_Rst();
return DHT22_Check();
}
实现图示效果的主程序为:
int main(void)
{
uint8_t senflag;
Delay_Init();
senflag=DHT22_Init();
Delay_Us(250);
app_OLED_Init();
OLED_Init();
OLED_Clear();
OLED_ShowString(0,0,"CH32V103 TEST",16);
OLED_ShowString(0,2,"OLED & DHT22",16);
Delay_Ms(2000);
OLED_Clear();
while(1)
{
if(!senflag)
{
DHT22_Read_Data(&temperature,&humidity);
OLED_ShowString(0,0,"Temp: C",16);
OLED_ShowNum(40,0,temperature,2,16);
OLED_ShowString(0,2,"Humi: %",16);
OLED_ShowNum(40,2,humidity,2,16);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
Delay_Ms(100);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
Delay_Ms(100);
}
}
}
以此为基础我们还可以为它配上按键来设置控制参数,进而通过继电器等来控制相应的读取来调节温湿度。
- 2021-02-07
-
回复了主题帖:
【RISC-V MCU CH32V103测评】RTC电子时钟
okhxyyo 发表于 2021-2-6 21:23
赞!!谢谢分享~~要是能拍个小视频就更好了
有时间拍一个
-
回复了主题帖:
【RISC-V MCU CH32V103测评】RTC电子时钟
qwqwqw2088 发表于 2021-2-6 21:03
支持一下
加油
- 2021-02-06
-
发表了主题帖:
【RISC-V MCU CH32V103测评】RTC电子时钟
本帖最后由 jennyzhaojie 于 2021-2-6 16:48 编辑
在CH32V103的内部配置了RTC计时器,把它与OLED显示屏结合起来就能构成一个RTC电子时钟。
实现电子时钟的主程序如下:
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
RTC_Init();
OLED_IO_Init();
OLED_Init();
OLED_Clear();
OLED_ShowString(0,0,"CH32V103",16);
OLED_ShowString(0,2,"OLED & RTC",16);
Delay_Ms(1000);
Delay_Ms(1000);
OLED_Clear();
OLED_ShowString(0,0,"20 - -",16);
OLED_ShowString(0,2," : :",16);
while(1)
{
OLED_ShowNum(16,0,calendar.w_year,2,16);
OLED_ShowNum(40,0,calendar.w_month,2,16);
OLED_ShowNum(64,0,calendar.w_date,2,16);
OLED_ShowNum(16,2,calendar.hour,2,16);
OLED_ShowNum(40,2,calendar.min,2,16);
OLED_ShowNum(64,2,calendar.sec,2,16);
Delay_Ms(1000);
}
}
相应的RTC初始化函数为:
u8 RTC_Init(void)
{
u8 temp=0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
if(BKP_ReadBackupRegister(BKP_DR1) != 0xA1A1)
{
BKP_DeInit();
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)
{
temp++;
Delay_Ms(20);
}
if(temp>=255)return 1;
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForLastTask();
RTC_WaitForSynchro();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
RTC_EnterConfigMode();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
RTC_Set(2021,1,25,2,18,01); /* Setup Time */
RTC_ExitConfigMode();
BKP_WriteBackupRegister(BKP_DR1, 0XA1A1);
}
else
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_WakeUpPinCmd(DISABLE);
RTC_WaitForSynchro();
//RTC_ITConfig(RTC_IT_ALR, ENABLE);
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
}
RTC_NVIC_Config();
RTC_Get();
return 0;
}
经程序编译下载后,其运行效果如图所示。
RTC电子时钟图
- 2021-02-02
-
回复了主题帖:
【RISC-V MCU CH32V103测评】驱动OLED屏显示
freebsder 发表于 2021-2-2 15:56
谢谢分享!显示屏的繁琐操作令人厌烦。
哈哈,在单片机和ARM上使用显示屏还算方便些,若换在FPGA上那就有些头大了,真称得上麻烦的。
-
回复了主题帖:
【RISC-V MCU CH32V103测评】驱动OLED屏显示
w494143467 发表于 2021-2-2 16:51
看这个屏幕有点像华大开发板上的屏幕哈~感谢分享!!!
-
发表了主题帖:
【RISC-V MCU CH32V103测评】驱动OLED屏显示
OLED屏是一种小巧的显示器件,其面对LCD1602等液晶显示屏也毫不逊色,显示的内容也并不少。此外,它按接口方式可分为I2C接口和SPI接口等,所占用的引脚也不多于LCD1602等。
这里选用的是I2C接口的OLED屏,它最有特点,用2个I/O口就能完成显示任务。
在掌握GPIO口使用的基础上,就可十分轻松地实现驱动OLED屏显示的目标。
这里的OLED屏与MCU的连接关系为:
SCL ---PA2
SDA--- PA3
驱动OLED屏所定义的输出高低电平的语句定义为:
#define SCL_high GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_SET)
#define SCL_low GPIO_WriteBit(GPIOA, GPIO_Pin_2, Bit_RESET)
#define SDA_high GPIO_WriteBit(GPIOA, GPIO_Pin_3, Bit_SET)
#define SDA_low GPIO_WriteBit(GPIOA, GPIO_Pin_3, Bit_RESET)
配置2个引脚为输出功能的函数为:
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3);
}
辅助驱动的相关函数为:
void IIC_Start()
{
SCL_high;
SDA_high;
SDA_low;
SCL_low;
}
void IIC_Stop()
{
SCL_low;
SDA_low;
SCL_high;
SDA_high;
}
void IIC_Wait_Ack()
{
SCL_high;
SCL_low;
}
OLED屏的初始化函数为:
void OLED_Init(void)
{
SCL_high;
SDA_high;
Delay_Ms(800);
OLED_WR_Byte(0xAE,OLED_CMD);//--display off
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address
OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
OLED_WR_Byte(0x81,OLED_CMD); // contract control
OLED_WR_Byte(0xFF,OLED_CMD);//--128
OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x1F,OLED_CMD);//--1/32 duty
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
OLED_WR_Byte(0x00,OLED_CMD);//
OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
OLED_WR_Byte(0xf0,OLED_CMD);//
OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
OLED_WR_Byte(0x22,OLED_CMD);//
OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
OLED_WR_Byte(0x49,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
OLED_WR_Byte(0x14,OLED_CMD);//
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
OLED_Clear();
}
显示字符串的函数为:
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size)
{
unsigned char j=0;
while (chr[j]!='\0')
{
OLED_ShowChar(x,y,chr[j],Char_Size);
x+=8;
if(x>120){x=0;y+=2;}
j++;
}
}
实现显示功能的主程序为:
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
OLED_IO_Init();
OLED_Init();
OLED_Clear();
OLED_ShowString(0,0,"CH32V103",16);
OLED_ShowString(0,2,"OLED TEST",16);
while(1) ;
}
经编译下载,其运行结果如下图所示。
运行效果图
-
回复了主题帖:
【RISC-V MCU CH32V103测评】更换PWM输出通道调节LED灯
okhxyyo 发表于 2021-2-2 09:34
赞!谢谢分享~~期待后面更多精彩内容!
感谢您的鼓励和支持!
-
回复了主题帖:
【RISC-V MCU CH32V103测评】更换PWM输出通道调节LED灯
freebsder 发表于 2021-2-1 22:57
谢谢分享!期待后续!
- 2021-02-01
-
发表了主题帖:
【RISC-V MCU CH32V103测评】更换PWM输出通道调节LED灯
上一次介绍了用TIM1的CH1通道来控制LED灯产生呼吸灯效果,并提出来一个如何迁移PWM输出口的问题。
那如何来实现呢?
请见下图:
也就是说,我们只需改变输出的通道即可。要输出到PA9就选取CH2,要输出到PA10就选取CH3。
道理是好说,关键是该如何做呢?
遍寻TIM1_PWMOut_Init()函数也没见到CH1的影子呀!
void TIM1_PWMOut_Init( u16 arr, u16 psc, u16 ccp )
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );
TIM_TimeBaseInitStructure.TIM_Period = arr;
TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure);
#if (PWM_MODE == PWM_MODE1)
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
#elif (PWM_MODE == PWM_MODE2)
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
#endif
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = ccp;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init( TIM1, &TIM_OCInitStructure );
TIM_CtrlPWMOutputs(TIM1, ENABLE );
TIM_OC1PreloadConfig( TIM1, TIM_OCPreload_Disable );
TIM_ARRPreloadConfig( TIM1, ENABLE );
TIM_Cmd( TIM1, ENABLE );
}
经仔细观察,虽为找到CH1,却寻到了除TIM1之外还含有1的痕迹,原来它没有直接以CHx通道的形式给出,而是采用了相关函数调用的方式。
要变为CH2的通道输出,就调用函数TIM_OC2Init( TIM1, &TIM_OCInitStructure )和TIM_OC1PreloadConfig( TIM1, TIM_OCPreload_Disable );而要变为CH3的通道输出,就调用函数TIM_OC3Init( TIM1, &TIM_OCInitStructure )和TIM_OC3PreloadConfig( TIM1, TIM_OCPreload_Disable )。
难道这样修改就可以了吗?
让事实来说话吧,答案是否定的。
那又是为什么呢?
请上眼主函数,其内容如下:
int main(void)
{
u16 pwmval=0;
u8 a=1;
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n",SystemCoreClock);
TIM1_PWMOut_Init( 899, 0, 500 );
while(1)
{
Delay_Ms(10);
if(a) pwmval++;
else pwmval--;
if(pwmval >300) a =0;
if(pwmval==0) a =1;
TIM_SetCompare1(TIM1, pwmval);
}
}
关键就出在对功能没有实际价值的printf输出上,它可是实实在在地在占用PA9和PA10呀!将它删除,再运行程序一切搞定!有时BUG就在你眼皮底下,但可能要花半天的时间才能恍然大悟,原来如此。