STM32 LCD1602驱动程序

发布者:快乐飞翔最新更新时间:2016-04-29 来源: eefocus关键字:STM32  LCD1602  驱动程序 手机看文章 扫描二维码
随时随地手机看文章
#ifndef  LCD1602_STM32_H

#define  LCD1602_STM32_H

#define LCD_RS_1 GPIOE->BSRR=GPIO_Pin_0 //PE.0--(LCD)RS
#define LCD_RS_0 GPIOE->BRR =GPIO_Pin_0
#define LCD_RW_1 GPIOE->BSRR=GPIO_Pin_1 //PE.1--(LCD)RW
#define LCD_RW_0 GPIOE->BRR =GPIO_Pin_1
#define LCD_EN_1 GPIOE->BSRR=GPIO_Pin_2 //PE.2--(LCD)E
#define LCD_EN_0 GPIOE->BRR =GPIO_Pin_2
#define DATAOUT  GPIOD->ODR             //PD[0..7]--(LCD)D0~D7

#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint 
#define uint unsigned int
#endif

extern void delay_nms(unsigned long n);
extern void delay_nus(unsigned long n);

uint8_t LCD_busy(void); //读LCD忙碌状态,直到LCD1602不忙为止
void Wait_Leisure(void);//一直等待到LCD1602空闲
void LCD_WriteInitcmd(uchar cmd);//写入LCD初始化时的命令,不可以检测忙状态
void LCD_Writecmd(uchar cmd);//写指令到LCD1602,指令数据占一个字节
void LCD_Writedata(uchar dat);//写一字节数据到LCD1602
void LCD_pos(uchar pos);//设定显示位置 00h~27h,40h~47h
void LCD_Setpos(uchar row,uchar col);//根据习惯设定显示位置
void LCD_DispChar(char ch);//显示一个字符
void LCD_Setpos_DispChar(uchar row,uchar col,char ch);//在指定位置显示一个字符
void LCD_DispString(char str[]);//使LCD1602显示一个字符串,显示位置需提前设定
void LCD_Setpos_DispString(uchar row,uchar col,char str[]);//使LCD1602从指定位置开始显示一个字符串
void LCD_Dispnum(uint32_t num);//显示一个不超过8位的整数,显示位置需提前设置
void LCD_Setpos_Dispnum(uchar row,uchar col,uint32_t num);//在指定位置显示一个不超过8位的整数
void LCD_DispDecimal(uint32_t num,uchar dot);//显示一个有效位不超过8位的浮点数,显示位置需要提前设定
//在指定位置显示一个有效位不超过8位的浮点数
void LCD_Setpos_DispDecimal(uchar row,uchar col,uint32_t num,uchar dot);
//显示日历,显示日期与时间
void LCD_DispDateTime(uint32_t year,uchar month,uchar day,uchar hour,uchar min,uchar sec);
//显示秒表,显示时,分,秒,10毫秒,精确到10ms
void LCD_DispStopWatch(uchar hour,uchar min,uchar sec,uchar tenms);
//显示频率计,动态自动调整频率显示
void LCD_DispFreq(uint32_t freq);
void LCD_ShiftLeft(void);//屏幕整体左移一格,用于滚动显示
void LCD_ShiftRight(void);//屏幕整体右移一格,用于滚动显示
void LCD_Clear(void);//清屏,清除显示
void LCD_Return(void);//使光标还回原点位置
void LCD_Close(void);//关显示
void LCD_Open(void);//开显示
void LCD_FlickerChar(uchar row,uchar col);//使指定位置字符闪烁,不显示光标
void LCD_CloseFlicker(void);//关闭字符闪烁
void LCD_FlickerScreen(void);//屏幕秒闪烁一次

void LCD_Init(void);

#endif

 


#include "stm32f10x.h"
#include "LCD1602.h"
#ifndef  LCD1602_STM32_C
#define  LCD1602_STM32_C


uint8_t LCD_busy(void)
                        
 LCD_RS_0;
 delay_nus(1);
 LCD_RW_1;
 delay_nus(1);
 do
 {
  LCD_EN_0;
  delay_nus(200);
  LCD_EN_1;
  delay_nus(200);
 }
 while(GPIOD->IDR & 0x80);
 LCD_EN_0;
 return (uint8_t)0; 
}

void Wait_Leisure(void)
{
 LCD_busy();
}

void LCD_WriteInitcmd(uchar cmd)
                         
 LCD_RS_0;
 delay_nus(1);
 LCD_RW_0;
 delay_nus(1);
 DATAOUT = cmd;
 LCD_EN_0;
 delay_nus(300);
 LCD_EN_1;
 delay_nus(300);
 LCD_EN_0;
 delay_nms(2);
}

void LCD_Writecmd(uchar cmd)
                         
 while(LCD_busy());
 LCD_RS_0;    //对同一个寄存器的两次写入,中间延时一会
 delay_nus(1);
 LCD_RW_0;
 delay_nus(1);
 LCD_EN_0;
 delay_nus(300);//产生脉冲
 DATAOUT = cmd;
 LCD_EN_1;
 delay_nus(300);//必要的延时
 LCD_EN_0;    //下降沿,LCD1602开始工作
}

void LCD_Writedata(uchar dat) 
                        
 while(LCD_busy());//等待LCD1602空闲
 LCD_RS_1;
 delay_nus(1);
 LCD_RW_0;
 delay_nus(1);
 DATAOUT = dat;
 LCD_EN_1;  //先拉高
 delay_nus(300); //很重要的延时,经调试,延时300us以上才可以
 LCD_EN_0;       //下降沿,开始写入有效数据
}

void LCD_pos(uchar pos)
                        
 LCD_Writecmd(pos | 0x80);
}

void LCD_Setpos(uchar row,uchar col)
{
 if(row==1) LCD_Writecmd(col | 0x80);
 else LCD_Writecmd(col | 0xC0);
}

void LCD_DispChar(char ch)
{
 LCD_Writedata(ch);
}

void LCD_Setpos_DispChar(uchar row,uchar col,char ch)
{
 LCD_Setpos(row,col);
 LCD_Writedata(ch);
}

void LCD_DispString(char str[])
{
    uchar i=0;
 while(str[i] != '\0')
 {
    LCD_Writedata(str[i]);
    ++i;
 }
}

void LCD_Setpos_DispString(uchar row,uchar col,char str[])
{
 LCD_Setpos(row,col);
 LCD_DispString(str);
}

void LCD_Dispnum(uint32_t num)
{
   uint i=0,j,k=0,wei,q;
   char str[9];
   if(num>=10000000)wei=8;
   else if(num>=1000000)wei=7;
   else if(num>=100000)wei=6;
   else if(num>=10000)wei=5;
   else if(num>=1000) wei=4;
   else if(num>=100)wei=3;
   else if(num>=10) wei=2;
   else wei=1;
   for(i=wei;i>0;i--)
    q=1;
       j=1; //i=1时,q=1,得到个位
    for(;j     str[k++]=num/q +'0';
    num %= q;
   }
   str[k] = '\0'; //添加字符串结束标志
   LCD_DispString(str);//显示字符串
}

void LCD_Setpos_Dispnum(uchar row,uchar col,uint32_t num)
{
   LCD_Setpos(row,col); 
   LCD_Dispnum(num);
}

void LCD_DispDecimal(uint32_t num,uchar dot)
{
   uint i=0,j,k=0,wei,q;
   char str[10];
   if(num>=10000000)wei=8;
   else if(num>=1000000)wei=7;
   else if(num>=100000)wei=6;
   else if(num>=10000)wei=5;
   else if(num>=1000) wei=4;
   else if(num>=100)wei=3;
   else if(num>=10) wei=2;
   else wei=1;
   for(i=wei;i>0;i--)
    q=1;
       j=1; //i=1时,q=1,得到个位
    for(;j     str[k++]=num/q +'0';
    num %= q;
   }
   str[k] = '\0'; //添加字符串结束标志
   for(i=8;i>0;i--)
    if((str[i]>='0')&&(str[i]<='9')) break;
   }
   str[i+2]='\0';   //添加字符串结束符
   for(j=0;j    {
     str[i+1]=str[i];
   }
   str[i+1]='.';       //插入小数点
   LCD_DispString(str);//显示浮点小数
}

void LCD_Setpos_DispDecimal(uchar row,uchar col,uint32_t num,uchar dot)
{
  LCD_Setpos(row,col);
  LCD_DispDecimal(num,dot);
}

void LCD_DispDateTime(uint32_t year,uchar month,uchar day,uchar hour,uchar min,uchar sec)
{
 LCD_Setpos(1,0);
 LCD_DispString("Date:");
 LCD_Dispnum((uint32_t)year);
 LCD_DispChar('-');
 LCD_Dispnum((uint32_t)month);
 LCD_DispChar('-');
 LCD_Dispnum((uint32_t)day);
 LCD_Setpos(1,15);
 LCD_DispChar('*'); //第一行结束符显示
 LCD_Setpos(2,0);
 LCD_DispString("Time:");
 LCD_Dispnum((uint32_t)hour);
 LCD_DispChar(':');
 LCD_Dispnum((uint32_t)min);
 LCD_DispChar(':');
 LCD_Dispnum((uint32_t)sec);
 LCD_Setpos(2,15);
 LCD_DispChar('*'); //第二行结束符显示
}

void LCD_DispStopWatch(uchar hour,uchar min,uchar sec,uchar tenms)
{
 LCD_Setpos(1,0);
 LCD_DispString("Current Time:");
 LCD_Setpos(1,15);
 LCD_DispChar('*'); //第一行结束符显示
 LCD_Setpos(2,2);
 LCD_Dispnum((uint32_t)hour);
 LCD_DispChar(':');
 LCD_Dispnum((uint32_t)min);
 LCD_DispChar(':');
 LCD_Dispnum((uint32_t)sec);
 LCD_DispChar(':');
 LCD_Dispnum((uint32_t)tenms);
 LCD_Setpos(2,15);
 LCD_DispChar('*'); //第二行结束符显示
}

void LCD_DispFreq(uint32_t freq)
{
 LCD_Setpos(1,0);
 LCD_DispString("Current Freq:");
 LCD_Setpos(2,1); //显示位置
 if(freq>=1000000)
 {
  LCD_DispDecimal(freq,6);
  LCD_DispString("MHz");
 }
 else if(freq>=1000) 
 
  LCD_DispDecimal(freq,3);
  LCD_DispString("KHz");
 }
 else { LCD_Dispnum(freq);
     LCD_DispString("Hz");
 }
 LCD_Setpos(2,14);
 LCD_DispString("OK");
}
//屏幕整体左移一格,用于滚动显示
void LCD_ShiftLeft()
{
 LCD_Writecmd(0x18);
}
//屏幕整体右移一格,用于滚动显示
void LCD_ShiftRight(void)
{
 LCD_Writecmd(0x1C);
}
//清屏,清除显示
void LCD_Clear(void)
{
 LCD_Writecmd(0x01);
}
//使光标还回原点位置
void LCD_Return(void)
{
 LCD_Writecmd(0x02);
}
//关显示
void LCD_Close(void)
{
 LCD_Writecmd(0x08);
}
//开显示
void LCD_Open(void)
{
 LCD_Writecmd(0x0C);
}

void LCD_FlickerChar(uchar row,uchar col)
{
 LCD_Writecmd(0x0D);
 LCD_Setpos(row,col);
}
//关闭字符闪烁
void LCD_CloseFlicker(void)
{
 LCD_Writecmd(0x0C);
}
//屏幕秒闪烁一次
void LCD_FlickerScreen(void)
{
 LCD_Writecmd(0x08);//关显示
 delay_nms(500);
 LCD_Writecmd(0x0C);//开显示
 delay_nms(500);
}

void LCD_Init(void)
  
    delay_nms(200);           //延时20ms         
 LCD_WriteInitcmd(0x38);  //16*2显示,5*7点阵,8位数据
 delay_nms(10);
 LCD_WriteInitcmd(0x38);  //16*2显示,5*7点阵,8位数据
 delay_nms(5);
 LCD_WriteInitcmd(0x38);  //16*2显示,5*7点阵,8位数据
 delay_nms(5);
 LCD_WriteInitcmd(0x08);  //先关显示,后开显示
 delay_nms(5);
 LCD_WriteInitcmd(0x06);  //自动右移光标,0x04为左移光标
 delay_nms(5);
 LCD_WriteInitcmd(0x01);  //清除LCD的显示内容
 delay_nms(6);
 LCD_WriteInitcmd(0x0c);  //显示开,关光标;0x08为关显示
 delay_nms(5);
}

#endif  //防止多次编译


#include "stm32f10x.h"

#include "LCD1602.h"


#define PE00 (uint32_t *)0x40230180


//时钟配置函数 8MHz*9=72MHz
void RCC_Configuration()
{
    RCC_DeInit();
 RCC_HSEConfig(RCC_HSE_ON);//使能HSE
 if(RCC_WaitForHSEStartUp()==SUCCESS)
 {
    RCC_HCLKConfig(RCC_SYSCLK_Div1); //HCLK=SYSCLK
    RCC_PCLK2Config(RCC_HCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div2);
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
    RCC_PLLCmd(ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while(RCC_GetSYSCLKSource()!=0x08);
 }
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC|\
                    RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE,ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
}

//延时n us
void delay_nus(unsigned long n)
{
 unsigned long j;
 while(n--)
 { j=8;
   while(j--);
 }
}

//延时n ms
void delay_nms(unsigned long n)
{
 while(n--)
    delay_nus(1100);
}
//GPIO配置函数
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; 
  GPIO_Init(GPIOD, &GPIO_InitStructure);     //PD口OD输出
  GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //PE.0~2 OD输出 
  GPIO_Init(GPIOE, &GPIO_InitStructure);
}
///////////////////////////////////////////
int main()
{
    //uint32_t i=0;
 char str[]={"happy!"};
    RCC_Configuration();
 GPIO_Configuration();
 LCD_Init();
 LCD_Setpos_DispString(1,3,str);
 LCD_DispFreq(123456);
 LCD_FlickerChar(2,3);
 LCD_FlickerScreen();
 LCD_FlickerScreen();
 LCD_FlickerScreen();
 delay_nms(2000);
 LCD_CloseFlicker();
 while(1)
 {
 };
}

 

 

关键字:STM32  LCD1602  驱动程序 引用地址:STM32 LCD1602驱动程序

上一篇:ARM学习《十一》—不用库函数自己动手配置STM32中的DMA
下一篇:STM32 IAR工程->Keil MDK转换详解

推荐阅读最新更新时间:2024-03-16 14:52

STM32系统嘀嗒定时器实现1ms中断事件
int main() { //系统定时器实现周期性1000hz中断事件,即1ms SysTick_Config(SystemCoreClock / 1000); } void SysTick_Handler(void) { static uint32_t cnt=0; cnt++;//记500次之后,=500ms,点灯 if(cnt =500) { cnt=0; 灯亮; } } 最大的定时时间: 如果是168MHZ, 2^24 ÷ 168000000=99.86ms
[单片机]
STM32单片机上电后时钟的默认配置过程
写作原由:今日接手用stm32f100xx芯片开发的项目,以前用的是stm8s 和stm32f103xx芯片;因为在别人的项目代码的基础上做2次开发,但是发现那个代码main函数中没有对系统时钟的设置的相关函数,一直纳闷,但也没有深究,直至昨日 调试时出现串口收发数据出错,源代码在原项目的板子上串口发送、接收数据正常,同样程序在项目板子上收发的数据不正确, 两块板子芯片一样,串口收发管脚一样,最后发现原来板子外部晶振是8MHZ ,新板子外部晶振是12MHZ; 而在STM32固件库中,默认的外部晶振是8MHZ,由于时钟源不正确,导致波特率不正确,当然收发的数据也不正确了…..我勒个去!都怪自己平时看问题“不求甚解”。 波特率与
[单片机]
<font color='red'>STM32</font>单片机上电后时钟的默认配置过程
STM32各个系列时钟调高时出现异常案例
STM32用户反馈,使用STM32F103内部时钟,把系统时钟配置成64MHz单片机就不跑了,配置成36MHz程序就正常妥妥的,频率稍高点就容易导致死机。他贴出的代码如下:void RCC_Configuration(void) { RCC_DeInit();//将外设 RCC寄存器重设为缺省值 RCC_HSICmd(ENABLE);//使能HSI while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);//等待HSI使能成功 //FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //FLASH_SetLatency(FLASH
[单片机]
<font color='red'>STM32</font>各个系列时钟调高时出现异常案例
STM32:Flash擦除与读写操作(HAL库)
应用平台:STM32F030F4P6 ST官方库:STM32Cube_FW_F0_V1.9.0 背景知识 绝大多数的单片机和微控制器(ARM,x86),地址空间都是以字节为单位的,也就是说一个地址是一个字节。 Flash存储器有个特点,就是只能写0,不能写1。所以如果原来的地址有数据了,意味着有一些位为0,这些位就相当于无效了。所以必须写之前确保他们都为1,只有擦除才可以。另外每次擦除都必须擦除一个4K大小的扇区,这是flash的特性所决定的。 对Flash操作前必需打开内部振荡器。 参考:stm32的学习—FLASH的操作和使用 STM32F030F4P6的Flash存储简介 STM32F030F4P6硬件配置:  
[单片机]
WindowsNT4.0下设备驱动程序的开发与应用
    摘要: 介绍了Windows NT4.0内核模式设备驱动程序开发中的一般性过程。通过提供一个最小化驱动程序的核心代码,解释各组成部分的结构功能和使用方法。在实践中,结合自身的开发需要,可编写出具有实用价值的驱动程序。     关键词:Win32子系统 设备驱动 系统注册表 I/O请求包     Windows NT 以其安全、稳定及界面友好等特性逐渐成为工业控制领域的前台操作系统。面对工业控制中大量采用的串/并行通信及总线控制等技术,要求用户不断开发出满足自身需要的硬件设备,同时又要求用户应用程序与这些硬件设备进行通信,发送控制命令,读取状态信息等等。Windows NT出于安全性、
[嵌入式]
STM32_GPIO之按键输入
/* 名称:STM32_GPIO之按键输入 说明:这个实验是GPIO的输入功能。基本的思路和51单片机差不多。也是 操作相应的IO口,不过不同的是对于独立按键输入实验来说,51单片机是 需要一开始把待检测的IO口设置成高电平,然后检测其何时被拉低。而对 于STM32来说,其GPIO端口就可以设置成上拉输入,即不需要再人为的把对 应的对应的IO口设置成高电平,硬件电路会自动把对应端口引脚拉成高电 平。 还有一点关于条件编译要说的:这个ifndef… #endif 一般用在头文件中。书上说为了防止重复编译。就我目前了解的来看,在实际应用中,如果在两个.c源文件中都include了一个头文件,那么好像加不加这个条件编译
[单片机]
STM32:简单位带操作
STM32 1.说在前面 1.最近刚刚在学stm32,第一个问题就是配置文件(HARDWARE)的问题,在HARDWARE中只存储着.c文件,然而以前因为不正确的设置方式,虽然代码逻辑没错但是还是跑不出来,所以,一定要使用标准的配置方式 2.位带操作 1.以前使用51的时候,设置高低电平的时候只要给相应的引脚设置1或0就可以配置高低电平,对于32而言,要不使用设置库函数,要不直接对寄存器进行操作,但是,通过位带操作,也可以实现相对简单的操作; 2.原理: 在stm32中对一个引脚进行设置是不存在的,但是可以把一个位膨胀成为32位的地址,然后对地址进行相应的操作; 位带区:想操作的相应io口内存所在区
[单片机]
stm32gpio的工作模式
1、推挽输出 可以输出高、低电平,连接数字器件;推挽结构一般是指两个三极管分别受两个互补 信号 的控制,总是在一个三极管导通的时候另一个截止。高低电平由 IC 的 电源 决定。 推挽电路是两个 参数 相同的三极管或 MOSFET ,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌 电流 ,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。 2、开漏输出 输出端相当于三极管的集电极,要得到高电平状态需要上拉 电阻 才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。 3、浮空输入 对于浮空输
[单片机]
stm32gpio的工作模式
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved