你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

查看: 2420|回复: 2

[STM32L4+] [STM32L4+实验]六、GPIO控制LED闪烁和驱显黑白LCD

[复制链接]

82

主题

636

回帖

121

蝴蝶豆

版主

最后登录
2020-7-12
发表于 2018-1-4 14:45:32 | 显示全部楼层 |阅读模式
[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秒左右。显示方式是正显正色,取反是背景色。这也是为了以后不再针对显示屏做功课了。

61动画

61动画

62

62

63

63

64

64
回复

使用道具 举报

64

主题

744

回帖

23

蝴蝶豆

实习版主

最后登录
2020-12-8
发表于 2018-1-4 17:35:51 | 显示全部楼层
屏幕不错
回复 支持 反对

使用道具 举报

82

主题

636

回帖

121

蝴蝶豆

版主

最后登录
2020-7-12
 楼主| 发表于 2018-1-4 21:31:34 | 显示全部楼层

谢谢夸赞,这款是老掉牙的的黑白显示屏,102X65点阵,为了省电,将他降为一个LED的压降——大约2.2V工作,所以背光也较暗。但一共只有1mA多点。
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版