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

查看: 2346|回复: 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管理
行使您的权利
官方最新发布
13245底部标题123相同标题
12底部标题123相同标题
33333底部标题123相同序号
3435底部标题-无链接
关注我们
st-img 微信公众号
st-img 手机版