沁恒 CH32V37VCT6评估板【R1】+LED_Flash+Nokia_LCD5110 - RISC-V MCU技术社区 - 电子技术论坛 - 广受欢迎的专业电子论坛
分享 收藏 返回

熊治坤 关注 私信

沁恒 CH32V37VCT6评估板【R1】+LED_Flash+Nokia_LCD5110

概述

CH32V307系列是基于32位RISC-V设计的互联型微控制器,配备了硬件堆栈区、快速中断入口,在标准RISC-V基础上大大提高了中断响应速度。加入单精度浮点指令集,扩充堆栈区,具有更高的运算性能。扩展串口UART数量到8组,电机定时器到4组。提供USB2.0高速接口(480Mbps)并内置了PHY收发器,以太网MAC升级到千兆并集成了10M-PHY模块。

系统框图

e1e19ab1f0a7b3c3c76bcff0ca7e86fd_BzTiK3UVAo6qzvBW38HAcFasGupJeNpbg1LXr2oO.jpeg

产品特点

  • 青稞V4F处理器,最高144MHz系统主频
  • 支持单周期乘法和硬件除法,支持硬件浮点运算(FPU)
  • 64KB SRAM,256KB Flash
  • 供电电压:2.5/3.3V,GPIO单元独立供电
  • 多种低功耗模式:睡眠、停止、待机
  • 上/下电复位、可编程电压监测器
  • 2组18路通用DMA
  • 4组运放比较器
  • 1个随机数发生器TRNG
  • 2组12位DAC转换
  • 2单元16通道12位ADC转换,16路触摸按键TouchKey
  • 10组定时器
  • USB2.0全速OTG接口
  • USB2.0高速主机/设备接口(480Mbps 内置PHY)
  • 3个USART接口和5个UART接口
  • 2个CAN接口(2.0B主动)
  • SDIO接口、FSMC接口、DVP数字图像接口
  • 2组IIC接口、3组SPI接口、2组IIS接口
  • 千兆以太网控制器ETH(内置10M PHY)
  • 80个I/O口,可以映射到16外部中断
  • CRC计算单元,96位芯片唯一ID
  • 串行2线调试接口
  • 封装形式:LQFP64M、LQFP100

开发板原理图

image.png

Nokia LCD5110接口

  1. RST ——复位
  2. CE —— 片选
  3. DC —— 数据/指令选择
  4. DIN —— 串行数据线
  5. CLK —— 串行时钟线
  6. VCC —— 电源输入(3.3v和5v均可)
  7. BL —— 背光控制端
  8. GND —— 地线

接口控制管脚配置如下

#define sce0 GPIO_WriteBit(GPIOA, GPIO_Pin_2,Bit_RESET) //片选CE

#define res0 GPIO_WriteBit(GPIOA, GPIO_Pin_1,Bit_RESET) //复位RST,0复位

#define dc0 GPIO_WriteBit(GPIOA, GPIO_Pin_3,Bit_RESET) //DC 1写数据,0写指令

#define sdin0 GPIO_WriteBit(GPIOA, GPIO_Pin_4,Bit_RESET) //数据DIN

#define sclk0 GPIO_WriteBit(GPIOA, GPIO_Pin_5,Bit_RESET) //时钟CLK

#define sce1 GPIO_WriteBit(GPIOA, GPIO_Pin_2,Bit_SET) //片选CE

#define res1 GPIO_WriteBit(GPIOA, GPIO_Pin_1,Bit_SET) //复位RST,0复位

#define dc1 GPIO_WriteBit(GPIOA, GPIO_Pin_3,Bit_SET) //DC 1写数据,0写指令

#define sdin1 GPIO_WriteBit(GPIOA, GPIO_Pin_4,Bit_SET) //数据DIN

#define sclk1 GPIO_WriteBit(GPIOA, GPIO_Pin_5,Bit_SET) //时钟CLK

#define LINGHT_OFF GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_SET)

#define LINGHT_ON GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_RESET)

程序实现功能说明

1-PA0控制LCD背光灯,为了看到效果,LCD控制背光闪烁2Hz;

2-PA6接入LED2,控制LED灯0.5S亮灭一次;

3-LCD测试显示是否成功,0.5S更新一次计数器并显示。

程序源代码

main函数

/********************************** (C) COPYRIGHT *******************************
* File Name          : main.c
* Author             : WCH
* Version            : V1.0.0
* Date               : 2021/06/06
* Description        : Main program body.
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/

/*
 *@Note
 GPIO例程:
 PA0推挽输出。

*/

#include "debug.h"
#include "5110LCD.h"
/* Global define */

/* Global Variable */

/*********************************************************************
 * @fn      GPIO_Toggle_INIT
 *
 * [url=home.php?mod=space&uid=2666770]@Brief[/url]   Initializes GPIOA.0
 *
 * [url=home.php?mod=space&uid=1141835]@Return[/url]  none
 */
void GPIO_Toggle_INIT(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void GPIO_LCD5110_INIT(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 |GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{
    u8 i = 0;
    u16 j=0;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    USART_Printf_Init(115200);
    printf("SystemClk:%d\\r\\n", SystemCoreClock);
    printf("GPIO Toggle and LCD5110 TEST\\r\\n");
    GPIO_Toggle_INIT();
    GPIO_LCD5110_INIT();
    LCD_Init();
      LCD_WriteString_en(0,0,"LCD5110 TEST");
      LCD_WriteString_en(0,1,"2023-08-27");
      LCD_WriteString_en(0,2,"_____________");
      LCD_WriteString_en(0,3,"Count:");
    while(1)
    {
        Delay_Ms(500);
        LCD_WriteNumber(0,4,j);
        j++;
        if(i==0){
            GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_RESET);
            GPIO_WriteBit(GPIOA, GPIO_Pin_6,Bit_RESET);
            i=1;
        }else{
            GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_SET);
            GPIO_WriteBit(GPIOA, GPIO_Pin_6,Bit_SET);
            i=0;
        }
    }
}

LCD驱动文件

LCD头文件

#ifndef __5110LCD_H
 #define __5110LCD_H
#include "debug.h"

 #define sce0   GPIO_WriteBit(GPIOA, GPIO_Pin_2,Bit_RESET)  //片选CE
 #define res0   GPIO_WriteBit(GPIOA, GPIO_Pin_1,Bit_RESET)  //复位RST,0复位
 #define dc0    GPIO_WriteBit(GPIOA, GPIO_Pin_3,Bit_RESET)	//DC 1写数据,0写指令
 #define sdin0  GPIO_WriteBit(GPIOA, GPIO_Pin_4,Bit_RESET)  //数据DIN
 #define sclk0  GPIO_WriteBit(GPIOA, GPIO_Pin_5,Bit_RESET)	//时钟CLK

 #define sce1   GPIO_WriteBit(GPIOA, GPIO_Pin_2,Bit_SET)		//片选CE
 #define res1   GPIO_WriteBit(GPIOA, GPIO_Pin_1,Bit_SET)		//复位RST,0复位
 #define dc1    GPIO_WriteBit(GPIOA, GPIO_Pin_3,Bit_SET)		//DC 1写数据,0写指令
 #define sdin1  GPIO_WriteBit(GPIOA, GPIO_Pin_4,Bit_SET)		//数据DIN
 #define sclk1  GPIO_WriteBit(GPIOA, GPIO_Pin_5,Bit_SET)		//时钟CLK

 #define LINGHT_OFF GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_SET)
 #define LINGHT_ON  GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_RESET)
	    
//void GPIO_Configuration_LCD(void);
void LCD_WriteByte(uint8_t dt, uint8_t command);
void LCD_Init(void);
void LCD_Set_XY(uint8_t X, uint8_t Y);
void LCD_Clear(void);
void LCD_WriteChar(uint8_t X,uint8_t Y,uint8_t c);
void LCD_WriteString_en(uint8_t X,uint8_t Y,char *s);
void LCD_WriteNumber(uint8_t x,uint8_t y, unsigned long number);
//void LCD_write_chinese_string(uint8_t X, uint8_t Y,
//                              uint8_t ch_with,uint8_t num,
//							  uint8_t line,uint8_t row);
void LCD_Write_cn(uint8_t row, uint8_t page,uint8_t c); //row:列 page:页 dd:字符

//void delay_ms(int t);
#endif

LCD函数实现

#include "5110LCD.h"

 //----------------------------------英文字符库-------------------------------------
// 6 x 8 font
// 1 pixel space at left and bottom
// 位置 = (ASCII - 32)*6
//----------------------------------------------------------------------------------
//****************************************************************************************************
// 	英文字符大小
//****************************************************************************************************
#define WIDTH    6
#define HEIGHT   8
//****************************************************************************************************
// 中文字符大小
//****************************************************************************************************
#define WIDTH_CN	13
#define HEIGHT_CN	16
 
uint8_t lcd_display[]="0123456789";  

const uint8_t font[][6] =
{
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // sp
	{ 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 },   // !
	{ 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 },   // "
	{ 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #
	{ 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 },   // $
	{ 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 },   // %
	{ 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 },   // &
	{ 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 },   // '
	{ 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 },   // (
	{ 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 },   // )
	{ 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 },   // *
	{ 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 },   // +
	{ 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 },   // ,
	{ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 },   // -
	{ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 },   // .
	{ 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 },   // /
	{ 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E },   // 0
	{ 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 },   // 1
	{ 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 },   // 2
	{ 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 },   // 3
	{ 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 },   // 4
	{ 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 },   // 5
	{ 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 },   // 6
	{ 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 },   // 7
	{ 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 },   // 8
	{ 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E },   // 9
	{ 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 },   // :
	{ 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 },   // ;
	{ 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 },   // <
	{ 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 },   // =
	{ 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 },   // >
	{ 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 },   // ?
	{ 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E },   // @
	{ 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C },   // A
	{ 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 },   // B
	{ 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 },   // C
	{ 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C },   // D
	{ 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 },   // E
	{ 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 },   // F
	{ 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A },   // G
	{ 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F },   // H
	{ 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 },   // I
	{ 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 },   // J
	{ 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 },   // K
	{ 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 },   // L
	{ 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F },   // M
	{ 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F },   // N
	{ 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E },   // O
	{ 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 },   // P
	{ 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E },   // Q
	{ 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 },   // R
	{ 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 },   // S
	{ 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 },   // T
	{ 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F },   // U
	{ 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F },   // V
	{ 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F },   // W
	{ 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 },   // X
	{ 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 },   // Y
	{ 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 },   // Z
	{ 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 },   // [
	{ 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 },   // 55
	{ 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 },   // ]
	{ 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 },   // ^
	{ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 },   // _
	{ 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 },   // '
	{ 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 },   // a
	{ 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 },   // b
	{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 },   // c
	{ 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F },   // d
	{ 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 },   // e
	{ 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 },   // f
	{ 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C },   // g
	{ 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 },   // h
	{ 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 },   // i
	{ 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 },   // j
	{ 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 },   // k
	{ 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 },   // l
	{ 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 },   // m
	{ 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 },   // n
	{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 },   // o
	{ 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 },   // p
	{ 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC },   // q
	{ 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 },   // r
	{ 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 },   // s
	{ 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 },   // t
	{ 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C },   // u
	{ 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C },   // v
	{ 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C },   // w
	{ 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 },   // x
	{ 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C },   // y
	{ 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 },   // z
	{ 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 }    // horiz lines
};

//****************************************************************************************************
// 写一字节
//****************************************************************************************************

void LCD_WriteByte(uint8_t dt, uint8_t command)
{
	uint8_t i; 
	sce0;            //使能LCD
	if(command==0)            //传送命令
	   dc0;
	else
	   dc1;         //传送数据
	for(i=0;i<8;i++)
	{ 
		if(dt&0x80)
			sdin1;
		else
			sdin0;
		sclk0;
		dt=(uint8_t)(dt << 1);
		sclk1;
	}	
	dc1;
    sce1;//关闭LCD
	sdin1;
}
//****************************************************************************************************
// LCD初始化
//****************************************************************************************************
void LCD_Init(void)
{
	sce1;
	res0;//产生一个让LCD复位的低电平脉冲
  	//delay_ms(10);
	for(int j=0;j<100;j++){for(int i=0;i<4800;i++);}	//48M clock,100*0.1ms	
  	res1;
	for(int j=0;j<1000;j++){for(int i=0;i<4800;i++);}	//48M clock,1000*0.1ms
	LCD_WriteByte(0x21,0);//使用水平寻址,进入拓展指令
    LCD_WriteByte(0x13,0);//定液晶偏置系统 1:48
	LCD_WriteByte(0xbb,0);//设定设置Vop,相当于亮度 
    LCD_WriteByte(0x20,0);//芯片活动 使用基本指令并且水平寻址
	LCD_WriteByte(0x0c,0);//设定显示模式,正常显示
    LCD_Clear();
}

//---------------------------------------
//名称: 设置坐标函数
//参数:X:0-83 Y:0-5
//作者:huoenlai
//邮箱:1084170961@qq.com
//日期:2011/3/28  
//-----------------------------------------   
void LCD_Set_XY(uint8_t X, uint8_t Y)
{
    Y|=0x40;
    X|=0x80;
	LCD_WriteByte(Y, 0);// 列
	LCD_WriteByte(X, 0);// 行
	sce1;
} 
//****************************************************************************************************
// LCD清屏
//****************************************************************************************************

void LCD_Clear(void)
{
	uint8_t t,k;
	LCD_Set_XY(0,0);
	for(t=0;t<6;t++)
	{ 
		for(k=0;k<84;k++)
		{ 
			LCD_WriteByte(0x00,1);
				
		} 
	}
}
//****************************************************************************************************
// 写一个字符
//****************************************************************************************************
void LCD_WriteChar(uint8_t X,uint8_t Y,uint8_t c)
{
    uint8_t i,j ;
   const  uint8_t *map = &font[0][0];
    c -= 32; //变换
    map += c *( HEIGHT/8*WIDTH);
   
    for(i=0;i<HEIGHT/8;i++)
    {
        LCD_Set_XY(X, Y+i);
        for(j=0;j<WIDTH;j++)
	    LCD_WriteByte(*map++, 1);
    }
}

//****************************************************************************************************
// 写英文字符串 
//****************************************************************************************************
void LCD_WriteString_en(uint8_t X,uint8_t Y,char *s)
{
    uint8_t i=0,j=0;
    while (*s)
    {
        LCD_WriteChar(X, Y,*s++);
        X+=WIDTH;
        i++;  
        if(i>=(84/WIDTH))
		{
			X=0;
			Y+=HEIGHT;
			i=0;
			j++;
		}
		if(j>=(48/HEIGHT))
		{
		 return  ;
		}  
    }
 } 
//****************************************************************************************************
// 写一个任意数字
//****************************************************************************************************
void LCD_WriteNumber(uint8_t x,uint8_t y, unsigned long number)
{
    uint8_t num[10]={""},i,j,k;
    if(number==0)                   //number 0 时候
    {
        LCD_WriteChar(x, y,'0');
    }
    else
    {
        for(i=0;number>0;i++)
        {
            num[i]=lcd_display[number%10];//每位以字符表示
            number/=10; 
        }
        for(j=0;j<i/2;j++){k=num[j];num[j]=num[i-1-j];num[i-1-j]=k;}
        LCD_WriteString_en(x,y,num);
    }
}

//****************************************************************************************************

实际运行效果

开机前

1108d5bca5f2b5e105ed34879c51a3e.jpg

开机后

22a8c9c6e0de01da7aba87312399995.jpg

b8807befc62493811eb0ca057bbefe5.jpg

9d20766adab4d69f0d751d5d8b58465.jpg

4716fe708ff8afdf246107a0fcf946d.jpg

程序运行视频

见附件

回帖(1)

熊治坤

2023-8-27 22:06:51
补充一点:开发环境为MounRiver Studio Version: v1.90。直接采用官方EVT中GPIO_Toggle程序修改而来。主主要验证开发环境、板子是否正常运行、以及驱动LCD显示屏。还好一次性成功。
1

更多回帖

×
发帖