前言

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

关于51单片机实现的时钟可以参考我以前发表的博文,里面还有演示的视频链接

由于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的数据手册,其中有一个电压特性,如下图

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

硬件电路连接

 

程序设计

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

#define LCD_RS PAout(1)
#define LCD_RW PAout(4)
#define LCD_EN PAout(6)
#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位的状态

void LCD_GPIO_Config(void)
{
GPIO_InitTypeDef IO_Init; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOE,ENABLE); /*控制线初始化 : */
IO_Init.GPIO_Mode=GPIO_Mode_OUT; //输出
IO_Init.GPIO_OType=GPIO_OType_PP; //推挽模式
IO_Init.GPIO_Pin=GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_6;
IO_Init.GPIO_PuPd=GPIO_PuPd_UP; //
IO_Init.GPIO_Speed=GPIO_Speed_2MHz; //GPIO_Speed_2MHz
GPIO_Init(GPIOA,&IO_Init); /*数据线初始化*/
IO_Init.GPIO_Mode=GPIO_Mode_OUT;
IO_Init.GPIO_OType=GPIO_OType_OD; //开漏输出可双向
IO_Init.GPIO_Pin=LCD_DB;
IO_Init.GPIO_PuPd=GPIO_PuPd_UP; //上拉
IO_Init.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOE,&IO_Init);
/*测试 : 高电平3.3v
LCD_RS=1;
LCD_RW=1;
LCD_EN=1;
GPIO_SetBits(GPIOE,LCD_DB); */
}

3.实现P1=0xff功能的函数,带参数

void GPIO_OutData(u8 Dat)
{
u16 tmp;
tmp = 0;
tmp =Dat;
tmp <<= 8; //数据左移到高8位
GPIO_Write(GPIOE,tmp); //数据写入到GPIOE高8位
}

4.检测LCD是否忙

void LCD_CheckBusy(void)
{
u8 sta;
GPIO_OutData(0xff);
LCD_RS=0;
LCD_RW=1;
do{
LCD_EN=1;
delay_ms(5);
sta = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_15);
LCD_EN =0;
}while(sta & 0x80);
}

5.向LCD写一字节数据

/* LCD_RS = 1, LCD_RW = 0 */
void LCD_WriteData(u8 Dat)
{ LCD_CheckBusy(); //忙则等待
LCD_RS=1;
LCD_RW=0;
GPIO_OutData(Dat);
LCD_EN=1;
delay_ms(1);
LCD_EN = 0; }

6.向LCD写一字节命令

/*LCD_RS = 0, LCD_RW = 0*/
void LCD_WriteCmd(u8 Cmd)
{
LCD_CheckBusy(); //忙则等待
LCD_RS = 0;
LCD_RW = 0;
GPIO_OutData(Cmd);
LCD_EN = 1;
delay_ms(1);
LCD_EN = 0;
}

7.LCD初始化

void LCD_Init(void)
{
LCD_WriteCmd(0x38);
LCD_WriteCmd(0x0C);
LCD_WriteCmd(0x06); /*显示光标移动设置*/ delay_ms(1);
LCD_WriteCmd(0x01); /*显示清屏*/
}

8.LCD清屏

void LCD_ClearScrren(void)
{
LCD_WriteCmd(0x01);
}

9.根据xy坐标,写入对应的数据位置

void LCD_SetCursor(u8 x, u8 y)
{
u8 addr;
if (y == 0)
addr = 0x00 + x;
else
addr = 0x40 + x;
LCD_WriteCmd(addr | 0x80);
}

10.根据xy坐标显示一个字符

void LCD_DisChar(u8 x,u8 y,u8 ch)
{
LCD_SetCursor(x,y); //字符显示位置设定
LCD_WriteData(ch);
}

11.显示两位的数字

void LCD_DisNumber(u8 x,u8 y,u8 Num)
{
LCD_SetCursor(x,y);
LCD_WriteData(0x30+Num/10);
LCD_SetCursor(x+1,y);
LCD_WriteData(0x30+Num%10);
}

12.显示字符串

void LCD_DisString(u8 x,u8 y,u8 *str)
{
LCD_SetCursor(x, y);
while(*str != '\0')
{
LCD_WriteData(*str++);
}
}

主函数

int main(void)
{
delay_init(168);
LED_Init(); LCD_GPIO_Config();
LCD_Init();
LCD_ClearScrren();
while(1)
{
delay_ms(500);
LED1_ON;
LCD_DisString(0,0,"abcdefghijklmnop");
delay_ms(500);
LED1_OFF;
LCD_DisNumber(0,1,56);
LCD_DisChar(2,1,'a');
LCD_DisString(3,1," Hello World!");
}
}

实际显示效果:

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

总结:

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

参考资料:

 
 程序源码下载链接: https://pan.baidu.com/s/1hsvEBcg 密码: fk3b

欢迎查看我以前的单片机学习笔记:

 
 
 
以上是我学习过程的一些个人理解,有不对或不准确的地方,欢迎各位大神指正。
 
2017年4月23日14:24:45
 欢迎大家关注我的个人博客

微信扫码关注我的公众号

不定期更新个人学习笔记和技术总结,欢迎大家互相学习交流!

STM32实战应用(一)——1602蓝牙时钟1液晶的显示测试的更多相关文章

  1. [CXF REST标准实战系列] 二、Spring4.0 整合 CXF3.0,实现测试接口(转)

    转自:[CXF REST标准实战系列] 二.Spring4.0 整合 CXF3.0,实现测试接口 文章Points: 1.介绍RESTful架构风格 2.Spring配置CXF 3.三层初设计,实现W ...

  2. STM32学习笔记(六) SysTick系统时钟滴答实验(stm32中断入门)

    系统时钟滴答实验很不难,我就在面简单说下,但其中涉及到了STM32最复杂也是以后用途最广的外设-NVIC,如果说RCC是实时性所必须考虑的部分,那么NVIC就是stm32功能性实现的基础,NVIC的难 ...

  3. STM32学习笔记(一)时钟和定时器

    由于近期在准备海洋航行器比赛,正好趁此机会学习一下ARM,看到周围很多同学都在使用32,所以我也买了一块STM32F103ZET6,准备好好地学习一下. STM32的时钟系统相当的复杂,包含了5个时钟 ...

  4. sTM32 使用TIMx_CH1作为 Tx1F_ED 计数器时钟

    环境:iar arm 5.3 stm32f103vbt6 使用PA.8 外部输入10Mhz的方波.可从systick中断得到数据4. 4×5000(预分频值)×1000(tick中断时间)=20MHz ...

  5. STM32 mdk软件仿真时过不去时钟的问题

    stm32的程序用MDK软件仿真时,由于系统时钟初始化函数里有个等待系统时钟准备好的循环,所以过不去. 设置方式如下:这么设置之后仿真时就可以直接进入main函数了.

  6. 【STM32系列汇总】小白博主的STM32实战快速进阶之路(持续更新)

    我把之前在学习和工作中使用STM32进行嵌入式开发的经验和教程等相关整理到这里,方便查阅学习,如果能帮助到您,请帮忙点个赞: 本文的宗旨 STM32 只是一个硬件平台,同样地他可以换成MSP430,N ...

  7. STM32—时钟树(结合系统时钟函数理解)

    时钟树的概念: 我们可以把MCU的运行比作人体的运行一样,人最重要的是什么?是心跳! 心脏的周期性收缩将血液泵向身体各处.心脏对于人体好比时钟对于MCU,微控制器(MCU)的运行要靠周期性的时钟脉冲来 ...

  8. STM32 STOP模式唤醒后的时钟

    进了STOP模式后,PLL停掉了,所以,如果开始的时钟配置,用的是PLL,那么唤醒后,需要重新配置RCC. 如果使用的是PLL,及时是用MSI作为时钟源,放大出来的,比如4M的MSI,PLL放大到48 ...

  9. ArcGIS Server 10.2 实战(三)图层标注及图例中文显示乱码的解决

    发布的图层中不可避免的使用到中文来标注,默认设置下,ArcGIS Server不支持中文的,中文标注显示成乱码,主要是编码的问题,需要把手动把编码改为UTF-8. ArcGIS Server 10.2 ...

随机推荐

  1. String字符串截取跟替换经典案例

    分享下今天的一个面试题吧!不算有难度,但是没做出来 题目:将String  str="姓名:武亚伟,年龄:27,地址:西安市": 输出结果为:姓名=武亚伟 年龄=27 地址=西安市 ...

  2. win8和ubuntu双系统

    硬盘安装的话只要分够内存和做好开机启动项就好了,u盘安装要注意分区(挂载)了推荐: http://wenku.baidu.com/view/5052f19b51e79b8968022623.html ...

  3. MySQL+SSM+Ajax上传图片问题

    第一次写上传图片的代码,碰到很多问题.昨天做了整整一天,终于在晚上的时候成功了.大声欢呼. 但是,做完之后,还是有很多问题想不通.所以在这里也算是写个笔记,日后忘记了可以回顾,也算请教各路朋友.(^_ ...

  4. WF学习思维导图

    原文 来自我的有道笔记-老文重发系列 如果配置加载核心服务,那么需要将持久化服务和跟踪服务放在一个数据库中!   1.用工作流的优点 a.提供将复杂任务分解的途径,通过将每个操作分解到活动中更便于业务 ...

  5. Linux系统启动过程详解

    启动第一步--加载BIOS当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它.这是因为BIOS中包含了CPU的相关信息.设备启动顺序信息.硬盘 ...

  6. 关于npm安装全局模块,require时报Error: Cannot find module 'XXX'的解决办法

    系统环境:centos 下午使用npm安装"cheerio",想搞爬虫玩玩. npm安装有两种模式: 本地 # npm install cheerio 全局 # npm insta ...

  7. Redis构建分布式锁

    1.前言 为什么要构建锁呢?因为构建合适的锁可以在高并发下能够保持数据的一致性,即客户端在执行连贯的命令时上锁的数据不会被别的客户端的更改而发生错误.同时还能够保证命令执行的成功率. 看到这里你不禁要 ...

  8. React-Native 开发(二) 在react-native 中 运用 redux

    前提: 一个小web前端,完全不会android 跟iOS 的开发,首次接触,有很多不懂的问题.请见谅. 环境: win7 上一篇 : React-Native 开发(一) Android环境部署,H ...

  9. iOS开发之类扩展

    在以往写代码时,我们经常是把声明写在.h文件中,把实现写在.m文件中,但是在实际开发中,如果把声明写在.h文件中会暴露程序很多属性(成员变量.成员变量的get和set方法),为了安全考虑,引入了类扩展 ...

  10. PyQt QListWidget修改列表项item的行高

    百度,谷歌之后都说用setHintSize(self,QCore.QSize(width,height)),然并卵,后来用qss修改就可以了,具体用法如下 # emaillist是我给QListWid ...