[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å¨ç»
62
63
64
STM32L4 超低功耗微系列及相关探索学习板介绍
STM32L476程序烧录
【NUCLEO-L476RG开发】使用STM32L4开发板玩转心率传感器
[Nucleo-L4R5] STM32L4R5 驱动OLED
[Nucleo-L4R5] STM32L4R5 基于OLED显示二维码
STM32L432KC开箱测评------OLED显示
STM32L476建工程及点亮LED
【评测站】STM32L496G-DISCO - 高性价比的智能手表解决方案
【超低功耗STM32L4系列首秀】 收到板子了,
STM32L496G-DISCO的出厂源码在哪儿可以下载?
谢谢夸赞,这款是老掉牙的的黑白显示屏,102X65点阵,为了省电,将他降为一个LED的压降——大约2.2V工作,所以背光也较暗。但一共只有1mA多点。