【解决方案】STM32L152单片机驱动段码LCD屏,执行HAL_LCD_Init函数失败返回HAL_TIMEOUT,长时间卡在LCD_FLAG_RDY的while循环里面的解决办法
发布日期:2021-06-29 10:16:54 浏览次数:4 分类:技术文章

本文共 5536 字,大约阅读时间需要 18 分钟。

STM32L152单片机驱动段码LCD屏,HAL_LCD_Init函数执行失败,卡在LCD_FLAG_RDY里面,函数返回HAL_TIMEOUT

/*!< Wait Until the LCD Booster is ready */while(__HAL_LCD_GET_FLAG(hlcd, LCD_FLAG_RDY) == RESET){  if((HAL_GetTick() - tickstart ) > LCD_TIMEOUT_VALUE)  {       hlcd->ErrorCode = HAL_LCD_ERROR_RDY;      return HAL_TIMEOUT;  }}

也就是LCD初始化过程中,LCD_SR_RDY位始终为0,这表明电压调节器不能正常工作。

 

在STM32L152单片机中,LCD和RTC是共用一个时钟。CubeMX生成的LCD初始化代码里面,选择LCD时钟的代码如下:

PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LCD;PeriphClkInit.LCDClockSelection = RCC_RTCCLKSOURCE_LSI;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){  Error_Handler();}

然而点进HAL_RCCEx_PeriphCLKConfig函数一看,函数里面只有下面这句话:

__HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);

也就是说根本就没有用到LCDClockSelection这个成员,库里面实际使用的是RTCClockSelection成员

调试程序也会发现,RCC_CSR_RTCSEL为0x00,没有设置为0x02,LCD外设根本就没有得到LSI时钟!

所以代码应该改成

PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);

这样LCD时钟才能选择成功,问题就解决了。

这完完全全是HAL库的BUG导致的问题

另外,LCD选择的是内部参考电压(LCD_VOLTAGESOURCE_INTERNAL),所以VLCD引脚上接的是1μF的电容到GND。VLCD引脚没有接VCC。

 

【完整代码】

#include 
#include "common.h"#include "LCDSEG.h"#define LCDSEG_A 0x80#define LCDSEG_B 0x40#define LCDSEG_C 0x20#define LCDSEG_D 0x10#define LCDSEG_E 0x08#define LCDSEG_F 0x04#define LCDSEG_G 0x02#define LCDSEG_TABLE_L 0x1c#define LCDSEG_TABLE_O lcdseg_table[0]#define LCDSEG_TABLE_H 0x6e#define LCDSEG_TABLE_I 0x0cconst static uint8_t lcdseg_table[10] = {0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0, 0xfe, 0xf6};LCD_HandleTypeDef hlcd;void LCDSEG_DisplayBatteryIcon(int enabled){ HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER0, 0x32d, (enabled) ? _BV(4) : 0); HAL_LCD_UpdateDisplayRequest(&hlcd);}void LCDSEG_DisplayBuzzerIcon(int enabled){ HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER0, 0x13d, (enabled) ? _BV(9) : 0); HAL_LCD_UpdateDisplayRequest(&hlcd);}void LCDSEG_DisplayTemperature(double temp){ int num; uint16_t seg[3]; uint32_t output[3] = {0}; num = (int)((temp + 0.05) * 10); // 保留一位小数, 四舍五入 if (num >= 0 && num <= 999) { seg[0] = lcdseg_table[num / 100]; // 十位 seg[1] = lcdseg_table[num % 100 / 10]; // 个位 seg[2] = lcdseg_table[num % 10]; // 十分位 output[0] |= _BV(3); // 小数点 } else { seg[0] = 0; if (num < 0) { seg[1] = LCDSEG_TABLE_L; seg[2] = LCDSEG_TABLE_O; } else { seg[1] = LCDSEG_TABLE_H; seg[2] = LCDSEG_TABLE_I; } } if (seg[0] & LCDSEG_D) output[0] |= _BV(8); if (seg[1] & LCDSEG_D) output[0] |= _BV(5); if (seg[2] & LCDSEG_D) output[0] |= _BV(2); if (seg[0] & LCDSEG_E) output[1] |= _BV(9); if (seg[0] & LCDSEG_G) output[1] |= _BV(8); if (seg[0] & LCDSEG_C) output[1] |= _BV(7); if (seg[1] & LCDSEG_E) output[1] |= _BV(6); if (seg[1] & LCDSEG_G) output[1] |= _BV(5); if (seg[1] & LCDSEG_C) output[1] |= _BV(4); if (seg[2] & LCDSEG_E) output[1] |= _BV(3); if (seg[2] & LCDSEG_G) output[1] |= _BV(2); if (seg[2] & LCDSEG_C) output[1] |= _BV(1); if (seg[0] & LCDSEG_F) output[2] |= _BV(9); if (seg[0] & LCDSEG_A) output[2] |= _BV(8); if (seg[0] & LCDSEG_B) output[2] |= _BV(7); if (seg[1] & LCDSEG_F) output[2] |= _BV(6); if (seg[1] & LCDSEG_A) output[2] |= _BV(5); if (seg[1] & LCDSEG_B) output[2] |= _BV(4); if (seg[2] & LCDSEG_F) output[2] |= _BV(3); if (seg[2] & LCDSEG_A) output[2] |= _BV(2); if (seg[2] & LCDSEG_B) output[2] |= _BV(1); HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER0, 0x211, output[0]); HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER2, 0x01, output[1]); HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER4, 0x01, output[2]); HAL_LCD_UpdateDisplayRequest(&hlcd);}void LCDSEG_EnableBackground(int enabled){ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, (enabled) ? GPIO_PIN_RESET : GPIO_PIN_SET);}void LCDSEG_Init(void){ GPIO_InitTypeDef gpio; RCC_OscInitTypeDef osc; RCC_PeriphCLKInitTypeDef periph_clock; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_LCD_CLK_ENABLE(); // 选择LCD时钟为LSI osc.OscillatorType = RCC_OSCILLATORTYPE_LSI; osc.LSIState = RCC_LSI_ON; osc.PLL.PLLState = RCC_PLL_NONE; HAL_RCC_OscConfig(&osc); periph_clock.PeriphClockSelection = RCC_PERIPHCLK_RTC; periph_clock.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; HAL_RCCEx_PeriphCLKConfig(&periph_clock); // PA1~3: LCD_SEG0~2, PA6~7: LCD_SEG3~4, PA8~10: LCD_COM0~2 gpio.Alternate = GPIO_AF11_LCD; gpio.Mode = GPIO_MODE_AF_PP; gpio.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &gpio); // PB0~1: LCD_SEG5~6, PB3~5: LCD_SEG7~9, PB10~13: LCD_SEG10~13 gpio.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13; HAL_GPIO_Init(GPIOB, &gpio); // 背光引脚 LCDSEG_EnableBackground(0); // 暂不开背光 gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Pin = GPIO_PIN_14; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &gpio); hlcd.Instance = LCD; hlcd.Init.Bias = LCD_BIAS_1_3; // 电平个数 hlcd.Init.Contrast = LCD_CONTRASTLEVEL_3; // 最高电压 hlcd.Init.Divider = LCD_DIVIDER_27; hlcd.Init.Duty = LCD_DUTY_1_3; // COM公共端个数 hlcd.Init.Prescaler = LCD_PRESCALER_16; HAL_LCD_Init(&hlcd); // 显示P2~4 HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER0, 0, 0x01); HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER2, 0, 0x01); HAL_LCD_Write(&hlcd, LCD_RAM_REGISTER4, 0, 0x01); HAL_LCD_UpdateDisplayRequest(&hlcd);}

 

转载地址:https://blog.csdn.net/ZLK1214/article/details/104664654 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:【方法】STM32F103C8单片机在Keil 5环境下使用C++编写程序,并将printf和cout重定向到串口
下一篇:VMWare虚拟机下Fedora30升级Fedora31,重启后无法启动系统,出现alloc magic is broken at 0xXXXX的错误

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月15日 05时24分55秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

干货分享 JVM 之第 4 篇 —— 掌握 Jmeter 压力测试工具,熟悉 Jconsole.exe 工具 2019-04-29
干货分享 JVM 之第 5 篇 —— 类加载器 2019-04-29
干货分享 JVM 之第 6 篇 —— SpringBoot2.0 框架性能调优 2019-04-29
基于 Hystrix 高并发服务限流第 1 篇 —— 必须了解的相关概念 2019-04-29
基于 Hystrix 高并发服务限流第 2 篇 —— 服务隔离(线程池隔离、信号量隔离) 2019-04-29
基于 Hystrix 高并发服务限流第 3 篇 —— 服务熔断、服务降级 2019-04-29
基于 Hystrix 高并发服务限流第 4 篇 —— 基于 Feign 实现服务熔断降级处理 2019-04-29
基于 Hystrix 高并发服务限流第 5 篇 —— Hystrix 监控 2019-04-29
Eureka 如何快速的、优雅的停止某个微服务 2019-04-29
Eureka 实现安全认证 2019-04-29
基于 Hystrix 高并发服务限流第 6 篇 —— 服务限流,基于 RateLimiter 实现 2019-04-29
Nginx 反向代理、负载均衡配置、Location正则表达式 2019-04-29
SpringBoot + WebSocket 实现前后端的收发消息 2019-04-29
SpringBoot 整合 JWT 实现统一认证 2019-04-29
SpringBoot 使用 CompletableFuture 实现非阻塞异步编程 2019-04-29
即刻就业:本科毕业如何快速高薪就业? 2019-04-29
即刻就业:java的应用程序有哪些,java程序有哪些编码规范,开发java应用程序有哪些步骤 2019-04-29
JAVA中的浮点数与二进制 2019-04-29
JAVA笔记(二)--Java初始 2019-04-29
JAVA笔记(三)--变量及运算符 2019-04-29