基于51单片机的知识总结,使用protues和keil共同学习。
我使用的是protues7.8 和 keil4,需要软件的联系我。
源码及protues仿真:https://download.csdn.net/download/sinat_33734313/11851282
LCD1602+交通灯
protues电路仿真
仿真元器件
LCD:LM016L
LED
仿真电路截图
硬件说明
1.LCD
1.1 引脚定义
1.2 基本操作时序:
读状态 输入:RS=L,RW=H,E=H 输出:DB0~DB7=状态字
写指令 输入:RS=L,RW=L,E=下降沿脉冲,DB0~DB7=指令码 输出:无
读数据 输入:RS=H,RW=H,E=H 输出:DB0~DB7=数据
写数据 输入:RS=H,RW=L,E=下降沿脉冲,DB0~DB7=数据 输出:无
1.3 关键指令:
清屏指令
功能:<1> 清除液晶显示器,即将 DDRAM 的内容全部填入"空白"的 ASCII
码 20H;
<2> 光标归位,即将光标撤回液晶显示屏的左上方;
<3> 将地址计数器(AC)的值设为 0。
进入模式设置指令
功能 : 设定每次定入 1 位数据后光标的移位方向 , 并且设定每次写入的一个字符是否移动。参数设定的情况如下所示:
位名 | 设置 |
---|---|
I/D | 0=写入新数据后光标左移,1=写入新数据后光标右移 |
S | 0=写入新数据后显示屏不移动,1=写入新数据后显示屏整体右移 1 个字符 |
显示开关控制指令
功能:控制显示器开/关、光标显示/关闭以及光标是否闪烁。参数设定的情
况如下:
位名 | 设置 |
---|---|
D | 0=显示功能关,1=显示功能开 |
C | 0=无光标,1=有光标 |
B | 0=光标闪烁,1=光标不闪烁 |
功能设定指令
功能:设定数据总线位数、显示的行数及字型。参数设定的情况如下:
位名 | 设置 |
---|---|
DL | 0=数据总线为 4 位 ,1=数据总线为 8 位 |
N | 0=显示 1 行,1=显示 2 行 |
F | 0=5×7 点阵/每字符,1=5×10 点阵/每字符 |
1.4 地址和屏幕对应关系
程序
/*-------------------------------------------
FileName:main.c
Function: MCU控制红绿灯
Description:模拟路口
LCD1602实时显示步进电机状态;
---------------------------------------------
Author: Ethan Chen
Date: 2019-10-10
-------------------------------------------*/
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
#include "lcd.h"
#include<intrins.h> //因为要用到左右移函数,所以加入这个头文件
#define FOSC 12000000L
#define T1MS (65535-FOSC/12/1000)
sbit X_Green=P1^0;
sbit X_Yellow=P1^1;
sbit X_Red=P1^2;
sbit Y_Green=P1^3;
sbit Y_Yellow=P1^4;
sbit Y_Red=P1^5;
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
u8 Second;
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(unsigned short i)
{
while(i--);
}
void Timer0Init(void)
{
TMOD|=0x01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0=T1MS>>8; //给定时器赋初值,定时1ms
TL0=T1MS;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
u8 PrintFlag = 0;
Second = 1;
Timer0Init();
LcdInit();
displayInit();
while(1)
{
if( Second >= 90 )
Second = 1;
if( Second <= 40 )
{
if( PrintFlag == 0 )
{
PrintFlag = 1;
X_Green = 0;
X_Yellow = 1;
X_Red = 1;
Y_Green = 1;
Y_Yellow = 1;
Y_Red = 0;
display(0, 2);
}
}
else if( Second <= 45 )
{
if( PrintFlag == 1 )
{
PrintFlag = 0;
X_Green = 1;
X_Yellow = 0;
X_Red = 1;
Y_Green = 1;
Y_Yellow = 1;
Y_Red = 0;
display(1, 2);
}
}
else if( Second <= 85 )
{
if( PrintFlag == 0 )
{
PrintFlag = 1;
X_Green = 1;
X_Yellow = 1;
X_Red = 0;
Y_Green = 0;
Y_Yellow = 1;
Y_Red = 1;
display(2, 0);
}
}
else
{
if( PrintFlag == 1 )
{
PrintFlag = 0;
X_Green = 1;
X_Yellow = 1;
X_Red = 0;
Y_Green = 1;
Y_Yellow = 0;
Y_Red = 1;
display(2, 1);
}
}
}
}
void Timer0() interrupt 1
{
static u16 i;
TH0=T1MS>>8; //给定时器赋初值,定时1ms
TL0=T1MS;
i++;
if(i==1000)
{
i=0;
Second ++;
}
}
/*-----------------------------
FileName:lcd.c
Function: LCD1602控制
Author: Ethan Chen
Date: 2019-10-9
------------------------------*/
#include "lcd.h"
#include "string.h"
/*******************************************************************************
* 函 数 名 : Lcd1602_Delay1ms
* 函数功能 : 延时函数,延时1ms
* 输 入 : c
* 输 出 : 无
* 说 名 : 该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/
void Lcd1602_Delay1ms(uint c) //误差 0us
{
uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
/*******************************************************************************
* 函 数 名 : LcdWriteCom
* 函数功能 : 向LCD写入一个字节的命令
* 输 入 : com
* 输 出 : 无
*******************************************************************************/
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //选择发送命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //放入命令
Lcd1602_Delay1ms(1); //等待数据稳定
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
/*******************************************************************************
* 函 数 名 : LcdWriteData
* 函数功能 : 向LCD写入一个字节的数据
* 输 入 : dat
* 输 出 : 无
*******************************************************************************/
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择输入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //写入数据
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
/*******************************************************************************
* 函 数 名 : LcdInit()
* 函数功能 : 初始化LCD屏
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void LcdInit() //LCD初始化子程序
{
LCD1602_E = 0;
LcdWriteCom(0x38); //开显示
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}
void displayInit(void)
{
uchar i;
LcdWriteCom(0x80);
for(i = 0; i < strlen(table0); i++)
{
LcdWriteData(table0[i]);
delay(5);
}
LcdWriteCom(0x80 + 0x40);
for(i = 0; i < strlen(table1); i++){
LcdWriteData(table1[i]);
delay(5);
}
}
void display(uchar oper, uchar dat)
{
if(oper == 0)
{
if(dat == 0)
{
LcdWriteCom(0x80 + strlen(table0));
LcdWriteData(table3[0]);
}
else if(dat == 1)
{
LcdWriteCom(0x80 + strlen(table0));
LcdWriteData(table3[1]);
}
}
if(oper == 1)
{
LcdWriteCom(0x80 + 0x40 + strlen(table1));
LcdWriteData(table2[dat]);
}
}