在线时间246 小时
UID252169
ST金币0
蝴蝶豆121
注册时间2016-10-24
版主
- 最后登录
- 2020-7-12
|
a0a.1 32b0c
[STM32L4+实验]六、GPIO控制LED闪烁和驱显黑白LCD
经过一番折腾+就当是学习吧,渐渐地对STM的开发板有了进一步的认识,于是开始做实验,当然实验是从基础开始,设想先驱动GPIO,使板载LED轮闪;接着驱动黑白LCD刷屏ASCII码。有了LCD,做其他实验就有了观察窗口,会很方便的。实际上我的新的学习和开发都是从LCD驱显开始。
在做这个实验之前确实想从STM32CubeMX开始——因为看本网站和其他介绍STM的网站,以及STMCU中文官网也极力推崇这款开发软件,实话实说从前天晚上开始,我也确实在用这款软件开始此款NUCLEO开发板之旅,不过理想美好,现实骨感,在整个过程中出现了许多问题,在提问过程中遇到不愉快的事,有好心的网友尽力解答,但因为问题不一样几乎无法重复,因此许多答非所问——不能说问的不好——因为你根本就不知道什么问题,问题从那开始发生,只能看到结果是一片的错!无奈退其次,采用惯用的实例入手,改代码实现——这是有根据的,因为成功的示例代码就是STM32Cube_FW_L4_V1.10.0提供的例程,寻遍历程有一个DMA中有驱动LED——GPIO驱动的代码,于是拷贝一份DMA->LED,以下所说的LED工程实际上就是DMA工程。那这个开刀。打开原始程序,按照关键代码函数纠源,一步一步终于将所有关于驱动GPIO的都找到了,并且驱动LCD成功。当然,首先是3个板载LED驱动成功,下边分两步来介绍:驱动LED显示,增加5个GPIO口驱显串口黑白LCD。以下的编程都在IAR8.20下完成,只是因为Keil[5.23或5.25pre]编译速度太太慢,以至于喝杯水的功夫Keil还在忙乎。
驱动LED,这个最为简单,因为按照说明,实例中的LED1,LED2,LED3都是已定义好的,可以拿来主义。首先将LED项目打开,打开main.c,将里面所有关于DMA的头文件、函数、语句都删除,下边直接给出代码:
//Includes
#include "main.h"
static void SystemClock_Config(void);
//GPIOInit PC7,PB7,PB14
void gpioInit(void){
BSP_LED_Init(LED1);
BSP_LED_Init(LED2);
BSP_LED_Init(LED3);
}
//LedTest
void ledTest(int ledNum){
switch(ledNum){
case 0:
BSP_LED_On(LED1);
BSP_LED_Off(LED2);
BSP_LED_Off(LED3);
break;
case 1:
BSP_LED_Off(LED1);
BSP_LED_On(LED2);
BSP_LED_Off(LED3);
break;
case 2:
BSP_LED_Off(LED1);
BSP_LED_Off(LED2);
BSP_LED_On(LED3);
break;
case 3:
BSP_LED_Off(LED1);
BSP_LED_Off(LED2);
BSP_LED_Off(LED3);
break;
}
}
int main(void){
int i;
HAL_Init();
//Configure the system clock to 120 MHz
SystemClock_Config();
gpioInit();
while (1){
for(i=0;i<4;i++){
ledTest(i);
HAL_Delay(300);
}
}
编译下载后,程序正常运行LED1~3轮流闪亮,最后全灭,见动画61。
接着参考LED驱动的方法,需要更改的地方有几处:
打开stm32l4xx_nucleo_144.h
在适合的位置[在LEDn之后即可,下同]先定义lcd类:
typedef enum{
LCD0 = 0,
sdat = LCD0,
LCD1 = 1,
sclk = LCD1,
LCD2 = 2,
sreg = LCD2,
LCD3 = 3,
sres = LCD3,
LCD4 = 4,
schi = LCD4
}Lcd_TypeDef;
此定义lcd可以用LCDn也可以用名称sdat...。在适当的位置定义LCDn的属性:
#define LCDn 5
#define LCD0_PIN GPIO_PIN_7
#define LCD0_GPIO_PORT GPIOD
#define LcD0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define LCD0_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
#define LCD1_PIN GPIO_PIN_6
#define LCD1_GPIO_PORT GPIOD
#define LCD1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define LCD1_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
#define LCD2_PIN GPIO_PIN_5
#define LCD2_GPIO_PORT GPIOD
#define LCD2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define LCD2_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
#define LCD3_PIN GPIO_PIN_4
#define LCD3_GPIO_PORT GPIOD
#define LCD3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define LCD3_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
#define LCD4_PIN GPIO_PIN_3
#define LCD4_GPIO_PORT GPIOD
#define LCD4_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define LCD4_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
#define LCDx_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == 0) {__HAL_RCC_GPIOD_CLK_ENABLE();} else {__HAL_RCC_GPIOB_CLK_ENABLE(); }} while(0)
#define LCDx_GPIO_CLK_DISABLE(__INDEX__) do { if((__INDEX__) == 0) {__HAL_RCC_GPIOD_CLK_DISABLE();} else {__HAL_RCC_GPIOB_CLK_DISABLE(); }} while(0)
最后将自己定义的函数声明在下边:
void BSP_LCD_Init(Lcd_TypeDef Lcd);
void BSP_LCD_DeInit(Lcd_TypeDef Lcd);
void BSP_LCD_On(Lcd_TypeDef Lcd);
void BSP_LCD_Off(Lcd_TypeDef Lcd);
实际上只有1,3,4行有用,不过多定义无害。接着打开stm32l4xx_nucleo_144.c文档,在适当位置添加:
GPIO_TypeDef *GPIO_PORT0[LCDn] = {LCD0_GPIO_PORT,LCD1_GPIO_PORT,LCD2_GPIO_PORT,LCD3_GPIO_PORT,LCD4_GPIO_PORT};
const uint16_t GPIO_PIN0[LCDn] = {LCD0_PIN,LCD1_PIN,LCD2_PIN,LCD3_PIN,LCD4_PIN};
之后依次增加以下几个函数:
//LCD GPIO Initial
void BSP_LCD_Init(Lcd_TypeDef Lcd){
GPIO_InitTypeDef GPIO_InitStruct;
//Enable the GPIO_LED Clock
LCDx_GPIO_CLK_ENABLE(Lcd);
//Configure the GPIO_LED pin
GPIO_InitStruct.Pin = GPIO_PIN0[Lcd];
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIO_PORT0[Lcd], &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIO_PORT0[Lcd], GPIO_PIN0[Lcd], GPIO_PIN_RESET);
}
void BSP_LCD_DeInit(Lcd_TypeDef Lcd){
GPIO_InitTypeDef GPIO_InitStruct;
//Turn off LCD
HAL_GPIO_WritePin(GPIO_PORT0[Lcd], GPIO_PIN0[Lcd], GPIO_PIN_RESET);
//DeInit the GPIO_LCD pin
GPIO_InitStruct.Pin = GPIO_PIN0[Lcd];
HAL_GPIO_DeInit(GPIO_PORT0[Lcd], GPIO_InitStruct.Pin);
}
//lcdPIN set High
void BSP_LCD_On(Lcd_TypeDef Lcd){
HAL_GPIO_WritePin(GPIO_PORT0[Lcd], GPIO_PIN0[Lcd], GPIO_PIN_SET);
}
//lcdPIN set Low
void BSP_LCD_Off(Lcd_TypeDef Lcd){
HAL_GPIO_WritePin(GPIO_PORT0[Lcd], GPIO_PIN0[Lcd], GPIO_PIN_RESET);
}
添加一个文件夹,将6903.h拷贝进来,并且在项目选项中默认指定,6903.h代码如下:
extern int k;
//6903 102X64LCD
const unsigned char asc2[][6]={//8x6 Dots 32-126[0-94]
{0x00,0x3E,0x45,0x49,0x51,0x3E},//0
{0x00,0x00,0x21,0x7F,0x01,0x00},//1
{0x00,0x31,0x43,0x45,0x49,0x31},//2
{0x00,0x22,0x49,0x49,0x49,0x36},//3
{0x00,0x04,0x0C,0x14,0x7F,0x04},//4
{0x00,0x72,0x51,0x51,0x51,0x4E},//5-5
{0x00,0x3E,0x49,0x49,0x49,0x06},//6
{0x00,0x40,0x43,0x4C,0x50,0x60},//7
{0x00,0x36,0x49,0x49,0x49,0x36},//8
{0x00,0x30,0x48,0x48,0x48,0x3F},//9
{0x00,0x1F,0x24,0x64,0x24,0x1F},//A-10
{0x00,0x41,0x7F,0x49,0x49,0x36},//B
{0x00,0x3E,0x41,0x41,0x41,0x22},//C
{0x00,0x41,0x7F,0x41,0x41,0x3E},//D
{0x00,0x41,0x7F,0x49,0x49,0x63},//E
{0x00,0x41,0x7F,0x49,0x5C,0x60},//F-15
{0x00,0x3E,0x41,0x45,0x47,0x24},//G
{0x41,0x7F,0x08,0x08,0x08,0x7F},//H
{0x00,0x00,0x41,0x7F,0x41,0x00},//I
{0x00,0x42,0x41,0x7F,0x40,0x40},//J
{0x00,0x41,0x7F,0x59,0x24,0x43},//K-20
{0x00,0x40,0x7F,0x41,0x01,0x03},//L
{0x00,0x7F,0x20,0x1E,0x20,0x7F},//M
{0x00,0x7F,0x30,0x18,0x06,0x7F},//N
{0x00,0x3E,0x41,0x41,0x41,0x3E},//O
{0x00,0x41,0x7F,0x49,0x48,0x30},//P-25
{0x00,0x3E,0x41,0x47,0x42,0x3D},//Q
{0x00,0x41,0x7F,0x49,0x4C,0x33},//R
{0x00,0x32,0x49,0x49,0x49,0x26},//S
{0x00,0x60,0x41,0x7F,0x41,0x60},//T
{0x00,0x7E,0x01,0x01,0x01,0x7E},//U-30
{0x00,0x7C,0x02,0x01,0x02,0x7C},//V
{0x00,0x7C,0x03,0x3C,0x03,0x7C},//W
{0x00,0x43,0x24,0x18,0x24,0x43},//X
{0x00,0x60,0x18,0x07,0x18,0x60},//Y
{0x00,0x63,0x45,0x49,0x51,0x63},//Z-35
{0x00,0x00,0x00,0x01,0x00,0x00},//.
{0x00,0x14,0x14,0x14,0x14,0x14},//=
{0x00,0x08,0x08,0x3E,0x08,0x08},//+
{0x00,0x08,0x08,0x08,0x08,0x08},//-
{0x00,0x00,0x00,0x24,0x00,0x00},//:-40
};
//Write Plus
void wri(void){BSP_LCD_Off(sclk);BSP_LCD_On(sclk);}
//Write a byte to lcd dt=data,com=reg/data
void b2l(unsigned char dt,unsigned char com){
unsigned char i;
if(com)BSP_LCD_On(sreg);else BSP_LCD_Off(sreg);
for(i=0;i<8;i++){
if(dt&0x80){BSP_LCD_On(sdat);}else{BSP_LCD_Off(sdat);};
dt=dt<<1;
wri();
}
}
//Set lcd display X,Y
void setXY(unsigned char X,unsigned char Y){
b2l(0x40 | Y,0);// column
b2l(0x80 | X,0);// row
}
//lcd Clear
void lcdClear(void){
unsigned char t,k;
setXY(0,0);
for(t=0;t<9;t++){for(k=0;k<102;k++){b2l(0x00,1);}}
}
//display a ASCII code
void c2l(unsigned char x,unsigned char y,unsigned char c){
unsigned char line;
setXY(x*6,y);
for (line=0;line<6;line++) b2l(asc2[c][line],1);
}
//LCD6903 Initial 102x64
void lcdInit(void){
BSP_LCD_Off(sres);
HAL_Delay(500);
BSP_LCD_On(sres);
HAL_Delay(500);
b2l(0x25,0);//00100 PD=1dcOn|=0Dcoff V=0Up|=1Left H==1
HAL_Delay(5);
b2l(0x14,0);//Plus width L000~111=1/6-1/7-1/8-1/9//14=1/7
HAL_Delay(5);
b2l(0xB4,0);//SET VOP~8.96V
HAL_Delay(5);
b2l(0x20,0);//PD=0,H=0,V=0
b2l(0x0C,0);//Set off
HAL_Delay(100);
}
//Display ASCII Test
void dispAsc(void){
int i,j;
for(i=0;i<8;i++){
for(j=0;j<17;j++){
c2l(j,i,k);
if(k>39){k=0;}else{k++;}
}
}
}
//END Files//
最后打开main.c文档,在头部增加头文件:
#include "6903.h"
一行外部变量定义:
int k=0;
在函数gpioInit()增加:
BSP_LCD_Init(LCD0);
BSP_LCD_Init(LCD1);
BSP_LCD_Init(LCD2);
BSP_LCD_Init(LCD3);
BSP_LCD_Init(LCD4);
在main函数前边增加:
gpioInit();
lcdInit();
lcdClear();
while循环中增加:
dispAsc();
for(i=0;i<4;i++){
ledTest(i);
HAL_Delay(300);
}
lcdClear();
编译下载结果见照片62。至此先期实验告一段落。看咱网站用串口TFTLCD驱显,一激动翻出老底也驱显一下,照片63、64 就是驱显2.4寸串口LCD刷屏ASCII码和自编点阵汉字的。代码就不上了,很简单。只是驱动是彩色的,型号为:LI3925/6,屏幕为2.4,320x240点阵,最大262K色,因为是串口,刷满一屏大约需要1秒左右。显示方式是正显正色,取反是背景色。这也是为了以后不再针对显示屏做功课了。
|
|