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

【经验分享】STM32实战应用(一)——1602蓝牙时钟1液晶的显示测试

[复制链接]
STMCU小助手 发布时间:2022-2-7 20:41
前言
从51到STM32F4学习这么久了,总算找到点头绪了,目前学习了GPIO,中断,定时器,看门狗的基本使用,所以想试着看看能不能做个什么东西,就是想复习一下最近学习的知识。正好上学期单片机课程设计做过一个可以蓝牙、按键校准、带温度显示的时钟,所以我想看能不能将程序移植到STM32上呢?说做就做,经过三天的时间,几次的程序修改和调试,终于成功了!

由于STM32内部定时器的精度还是很高的(一小时慢1s),所以就没有使用DS1302时钟芯片(关键是手里没有),显示上和课程设计做的有些不一样,没有增加日期和星期显示,就时间、闹钟和温度的显示。

今天先学习一下1602液晶的显示,那么如何用STM32控制LCD1602显示字符,字符串或数字呢?
1602液晶介绍
工业字符型液晶,能够同时显示16x02即32个字符。1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。市面上字符液晶大多数是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。

由于1602液晶是5V供电,引脚高电平为5v。不像51单片机IO输出高电平5v,STM32高电平只有3.3v,低电平0v,找到了1602的数据手册,里面居然没有说明高电平电压范围,到底能不能驱动呢?我又查找了1602驱动芯片HD44780的数据手册,其中有一个电压特性,如下图
1124009-20170423131826726-1458841834.png

可见用STM32的3.3v电平驱动显示完全没问题,看到这我就放心了,代码经过多次的修改后,终于成功显示了,所以还是要多看看数据手册。

硬件电路连接


1124009-20170423132248601-1684036602.png


程序设计
1.控制线宏定义,通过位带操作,以后就可以像51那样RS=1来操作了,是不是很熟悉呢?这里还将数据线的8个端口定义为了一个LCD_DB

  1. #define LCD_RS PAout(1)
  2. #define LCD_RW PAout(4)
  3. #define LCD_EN PAout(6)
  4. #define LCD_DB GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 |GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15
复制代码

2.LCD相连的GPIO配置,将数据线端口配置为OD(开漏)输出模式,可以做双向IO使用,在检测LCD是否忙时,需要读取D7位的状态
  1. void LCD_GPIO_Config(void)
  2. {
  3.     GPIO_InitTypeDef  IO_Init;
  4.    
  5.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOE,ENABLE);
  6.    
  7.     /*控制线初始化 : */
  8.     IO_Init.GPIO_Mode=GPIO_Mode_OUT;        //输出
  9.     IO_Init.GPIO_OType=GPIO_OType_PP;        //推挽模式
  10.     IO_Init.GPIO_Pin=GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_6;
  11.     IO_Init.GPIO_PuPd=GPIO_PuPd_UP;            //
  12.     IO_Init.GPIO_Speed=GPIO_Speed_2MHz;        //GPIO_Speed_2MHz
  13.     GPIO_Init(GPIOA,&IO_Init);
  14.    
  15.     /*数据线初始化*/
  16.     IO_Init.GPIO_Mode=GPIO_Mode_OUT;
  17.     IO_Init.GPIO_OType=GPIO_OType_OD;        //开漏输出可双向
  18.     IO_Init.GPIO_Pin=LCD_DB;
  19.     IO_Init.GPIO_PuPd=GPIO_PuPd_UP;            //上拉
  20.     IO_Init.GPIO_Speed=GPIO_Speed_2MHz;        
  21.     GPIO_Init(GPIOE,&IO_Init);                        
  22.     /*测试 : 高电平3.3v
  23.     LCD_RS=1;
  24.     LCD_RW=1;
  25.     LCD_EN=1;
  26.     GPIO_SetBits(GPIOE,LCD_DB); */
  27. }
复制代码


3.实现P1=0xff功能的函数,带参数
  1. void GPIO_OutData(u8 Dat)
  2. {
  3.     u16 tmp;
  4.     tmp = 0;
  5.     tmp =Dat;
  6.     tmp <<= 8;            //数据左移到高8位
  7.     GPIO_Write(GPIOE,tmp);        //数据写入到GPIOE高8位
  8. }
复制代码

4.检测LCD是否忙
  1. void LCD_CheckBusy(void)
  2. {
  3.     u8 sta;
  4.     GPIO_OutData(0xff);
  5.     LCD_RS=0;
  6.     LCD_RW=1;
  7.     do{
  8.         LCD_EN=1;
  9.         delay_ms(5);
  10.         sta = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_15);
  11.         LCD_EN =0;
  12.     }while(sta & 0x80);
  13. }
复制代码


5.向LCD写一字节数据
  1. /* LCD_RS = 1, LCD_RW = 0 */
  2. void LCD_WriteData(u8 Dat)
  3. {

  4.     LCD_CheckBusy(); //忙则等待
  5.     LCD_RS=1;
  6.     LCD_RW=0;
  7.     GPIO_OutData(Dat);
  8.     LCD_EN=1;
  9.     delay_ms(1);
  10.     LCD_EN = 0;
  11.    
  12. }
复制代码

6.向LCD写一字节命令
  1. /*LCD_RS = 0, LCD_RW = 0*/
  2. void LCD_WriteCmd(u8 Cmd)
  3. {
  4.     LCD_CheckBusy(); //忙则等待
  5.     LCD_RS = 0;
  6.     LCD_RW = 0;
  7.     GPIO_OutData(Cmd);   
  8.     LCD_EN = 1;
  9.     delay_ms(1);
  10.     LCD_EN = 0;     
  11. }
复制代码

7.LCD初始化
  1. void LCD_Init(void)
  2. {
  3.     LCD_WriteCmd(0x38);
  4.     LCD_WriteCmd(0x0C);
  5.     LCD_WriteCmd(0x06);    /*显示光标移动设置*/    delay_ms(1);
  6.     LCD_WriteCmd(0x01);    /*显示清屏*/
  7. }
复制代码

8.LCD清屏
  1. <div>void LCD_ClearScrren(void)</div><div>{</div><div>    LCD_WriteCmd(0x01);</div><div>}</div>
复制代码



9.根据xy坐标,写入对应的数据位置
  1. void LCD_SetCursor(u8 x, u8 y)
  2. {
  3.     u8 addr;
  4.     if (y == 0)
  5.         addr = 0x00 + x;
  6.     else
  7.         addr = 0x40 + x;
  8.     LCD_WriteCmd(addr | 0x80);
  9. }
复制代码

10.根据xy坐标显示一个字符
  1. void LCD_DisChar(u8 x,u8 y,u8 ch)
  2. {
  3.     LCD_SetCursor(x,y);        //字符显示位置设定
  4.     LCD_WriteData(ch);
  5. }
复制代码

11.显示两位的数字
  1. void LCD_DisNumber(u8 x,u8 y,u8 Num)
  2. {
  3.     LCD_SetCursor(x,y);
  4.     LCD_WriteData(0x30+Num/10);
  5.     LCD_SetCursor(x+1,y);
  6.     LCD_WriteData(0x30+Num%10);
  7. }
复制代码


12.显示字符串
  1. void LCD_DisString(u8 x,u8 y,u8 *str)
  2. {
  3.     LCD_SetCursor(x, y);
  4.     while(*str != '\0')
  5.     {
  6.         LCD_WriteData(*str++);
  7.     }
  8. }
复制代码

主函数
  1. int main(void)
  2. {
  3.     delay_init(168);
  4.     LED_Init();
  5.    
  6.     LCD_GPIO_Config();
  7.     LCD_Init();
  8.     LCD_ClearScrren();
  9.     while(1)
  10.     {
  11.         delay_ms(500);
  12.         LED1_ON;
  13.         LCD_DisString(0,0,"abcdefghijklmnop");
  14.         delay_ms(500);
  15.         LED1_OFF;
  16.         LCD_DisNumber(0,1,56);
  17.         LCD_DisChar(2,1,'a');
  18.         LCD_DisString(3,1," Hello World!");
  19.     }   
  20. }
复制代码


实际显示效果:

1124009-20170423140758382-1252243185.jpg

显示非常完美,和51驱动没有什么区别


总结:
实际运行时,不使用检测忙函数也行,1602显示正常了,接下来就是增加定时器显示时钟了。在设置IO口模式时,可以将模式设置为开漏模式,就可以实现双向IO的目的,即可输出,又可以读取外部输入。通过位带操作和宏定义就可以像51那样直接操作IO口输出高低电平了。



收藏 评论0 发布时间:2022-2-7 20:41

举报

0个回答

所属标签

相似技术帖

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