准备搞个自行车里程速度表,因为准备添加的功能过多,I/O脚不够,参考网上的资料搞了个4Bit数据接口的1602程序,结果才下载进单片机时还行,重启后立马显示乱码!上网查了N久,发现有两点可能导致这个问题!第一:初始化出错,第二:操作时序不正确!网上初始化有好几种,全都试了一遍,无效!后来根据太阳人网上的数据手册微调了一下时序,暂时稳定了!贴出程序请大家指正!
/*******************************************************************************
* 工 程 名: 自行车里程表
* 开始日期: 2012年05月06日
* 编 写 人: lilin
* 工程描述: 自用A3144E测速,LCD1602显示
*******************************************************************************
* 硬件描述:
* 单 片 机: C8051F330 DIP20
* 传 感 器: A3144E
* 显 示 器: LCD1602
* 硬件连接: D4——D7 P1.4——P1.7
RS P0.0
RW P0.1
E P0.2
*******************************************************************************/
/*******************************************************************************
* 版本记录: V0.1
* 功 能: LCD1602显示测试完成,8Bit数据线控制
* 待 改 进: 4Bit数据线控制,改进日期5-10---完成
*******************************************************************************/
#include <c8051f330.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
//预处理数值定义区
#define Delays_timer0 24121 //定时器延时时间2MS
#define Wheel_length 1.87 //自行车单周行程1.87M
#define Lcd_data P1 //1602数据口为单片机P1口,4位数据线接在P1.4-P1.7
/********************************变量定义区************************************/
//BIT数据定义区
sbit Lcd_rs=P0^0; //LCD1602 RS引脚接P0.0
sbit Lcd_rw=P0^1; //LCD1602 R/W引脚接P0.1
sbit Lcd_ee=P0^2; //LCD1602 E引脚接P0.2
//8位数据定义区
uint8 Soft_Id=0; //程序运行允许位,最高位为零速标志位;
uint8 Delays_lcd=0; //LCD1602延时参数;
uint8 Time_s=0; //时钟显示
uint8 Time_m=0;
uint8 Time_h=0;
//16位数据定义区
uint16 Mcu_time=0; //单片机定时器计数器;
uint16 Wheel_time=0; //单周车轮所需时间;
uint16 New_time=0; //最新采集的单周所需时间数据;
uint16 Old_time=0; //以前采集的单周所需时间数据;
uint16 Wheel_count=0; //自行车车轮转数计数;
uint16 Cycling_speed=0; //自行车速度(米/秒);
//数组定义区
/******************************函数区******************************************/
/*******************************************************************************
* 函 数 名: Mcu_Init()
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: 单片机相关初始化,HL振荡器、IO口、定时器
* 传入参数: 无
* 返回参数: 无
* 内部变量: 无
* 全局变量: 无
*******************************************************************************/
void Mcu_Init(void)
{
//系统时钟初始化 SYSCLK=24MHZ,内部HL振荡器使能
OSCICL += 4;
OSCICN |= ( 1<<7 );
while( !( OSCICN & 0x40 ) );
OSCICN |= 3;
CLKSEL = 0;
//禁止看门狗
PCA0MD &= 0xBF;
//I/O口初始化,P0.7为INT0,交叉开关跳过
P0MDIN=0xff;
P1MDIN=0xff;
P0MDOUT=0x00; //P0漏极开路输出
P1MDOUT=0x00; //P1漏极开路输出
P0SKIP=0x80; //P0引脚交叉开关跳过P0.7
P1SKIP=0x00;
XBR0=0x00;
XBR1=0x40; //交叉开关使能,引脚弱上拉
//INT0初始化,边缘触发,P0.7脚为INT0引脚
IT0=1;
IT01CF=0x07;
//定时器0初始化
//定时器0运行在16位重载模式,系统时钟
TMOD=0x01;
CKCON=0x04;
TH0=(65536-Delays_timer0)>>8;
TL0=(65536-Delays_timer0)&0xff;
TR0=1;
//开启Timer0,INT0中断
EX0=1;
ET0=1;
EA=1;
}
/*******************************************************************************
* 函 数 名: Delays_ms()
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: 系统运行过快,延时MS
* 传入参数: Dly_time:需要延时的MS数
* 返回参数: 无
* 内部变量: iii
* 全局变量: 无
*******************************************************************************/
void Delays_ms(uint8 Dly_time)
{
Delays_lcd=Dly_time+1;
while(Delays_lcd);
}
/*******************************************************************************
* 函 数 名: Check_lcd()
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: LCD1602忙状态检查,DB7=1
* 传入参数: 无
* 返回参数: P1
* 内部变量: 无
* 全局变量: 无
*******************************************************************************/
unsigned char Check_lcd(void)
{
uint8 temp1=0 ;
do
{
Lcd_rs = 0;
Lcd_rw = 1;
Lcd_ee = 0;
Lcd_ee = 1;
Delays_ms(2);
temp1=Lcd_data & 0xf0;
Delays_ms(1);
Lcd_ee = 0;
Delays_ms(1);
Lcd_ee = 1;
Delays_ms(2);
Lcd_ee = 0;
}
while(temp1 & 0x80);
return(Lcd_data);
}
/*******************************************************************************
* 函 数 名: Wcom_lcd()
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: Lcd1602写命令函数
* 传入参数: Lcd_com:命令代码 ,BuysC:是否要求忙检查
* 返回参数: 无
* 内部变量: 无
* 全局变量: 无
*******************************************************************************/
void Wcom_lcd(uint8 Lcd_com,uint8 BuysC )
{
if (BuysC) Check_lcd(); //根据需要检测忙
Lcd_rs = 0;
Lcd_rw = 0;
Lcd_ee = 0;
Lcd_ee = 1;
Lcd_data &= 0x0f;
Lcd_data |=(Lcd_com & 0xf0);
Delays_ms(2);
Lcd_ee = 0;
Delays_ms(1);
Lcd_ee = 1;
Lcd_data &= 0x0f;
Lcd_data |=((Lcd_com & 0x0f))<<4;
Delays_ms(2);
Lcd_ee = 0;
}
/*******************************************************************************
* 函 数 名: Wdat_lcd()
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: Lcd1602写数据函数
* 传入参数: Lcd_dat:需要写入的数据
* 返回参数: 无
* 内部变量: 无
* 全局变量: 无
*******************************************************************************/
void Wdat_lcd(unsigned char Lcd_dat)
{
Check_lcd(); //检测忙
Lcd_rs = 1;
Lcd_rw = 0;
Lcd_ee = 0; //延时
Lcd_ee = 1;
Lcd_data &= 0x0f;
Lcd_data |=(Lcd_dat & 0xf0);
Delays_ms(2);
Lcd_ee = 0;
Delays_ms(1);
Lcd_ee = 1;
Lcd_data &= 0x0f;
Lcd_data |=((Lcd_dat & 0x0f))<<4;
Delays_ms(2);
Lcd_ee = 0;
}
/*
unsigned char Rdat_lcd(void)
{
Lcd_rs = 1;
Delays_sys();
Lcd_rw = 1;
Delays_sys();
Lcd_ee = 0;
Delays_sys();
Lcd_ee = 0;
Delays_sys();
Lcd_ee = 1;
Delays_sys();
return(Lcd_data);
}
*/
/*******************************************************************************
* 函 数 名: DisplayOneChar
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: Lcd1602插入数据函数
* 传入参数: X:一行中的位置 ,Y:第几行,DData:需插入的数据
* 返回参数: 无
* 内部变量: 无
* 全局变量: 无
*******************************************************************************/
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y)
{
X |= 0x40; //当要显示第二行时地址码+0x40;
}
X |= 0x80; // 算出指令码
Wcom_lcd(X, 0); //这里不检测忙信号,发送地址码
Wdat_lcd(DData);
}
/*******************************************************************************
* 函 数 名: DisplayOneChar
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: Lcd1602插入数据函数
* 传入参数: X:一行中的位置 ,Y:第几行,DData:需插入的数据
* 返回参数: 无
* 内部变量: 无
* 全局变量: 无
*******************************************************************************/
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
while (DData[ListLength]>0x20) //若到达字串尾则退出
{
if (X <= 0xF) //X坐标应小于0xF
{
DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
ListLength++;
X++;
}
}
}
/*******************************************************************************
* 函 数 名: timer0()
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: 定时器0中断程序,系统自动调用
* 传入参数: 无
* 返回参数: 无
* 内部变量: 无
* 全局变量: Mcu_time,Wheel_time,Soft_Id
*******************************************************************************/
void timer0() interrupt 1
{
//重置Timer0寄存器
TH0=(65536-Delays_timer0)>>8;
TL0=(65536-Delays_timer0)&0xff;
//定时器计数器自加1
Mcu_time++;
//轮子单周所需时间计数
if(Soft_Id & 0x80)
{
Wheel_time++;
}
//Lcd1602延时
if(Delays_lcd >0)
{
Delays_lcd--;
}
}
/*******************************************************************************
* 函 数 名: INT0_ISR()
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: 外部中断0中断程序,系统自动调用
* 传入参数: 无
* 返回参数: 无
* 内部变量: 无
* 全局变量: Wheel_count,Wheel_time,Soft_Id,New_time,Old_time
*******************************************************************************/
void INT0_ISR(void) interrupt 0
{
Wheel_count++;
if(Soft_Id & 0x80)
{
Old_time =New_time;
New_time =Wheel_time;
}
else
{
Soft_Id |= 0x80;
Old_time =0;
New_time =0;
}
Wheel_time=0;
}
void Wcom_lcd_8(uint8 Lcd_com,uint8 BuysC )
{
if (BuysC) Check_lcd(); //根据需要检测忙
Lcd_rs = 0;
Lcd_rw = 0;
Lcd_ee = 0;
Delays_ms(1);
Lcd_ee = 1;
Lcd_data = Lcd_com;
Delays_ms(2);
Lcd_ee = 0;
}
/*******************************************************************************
* 函 数 名: Lcd_Init()
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: Lcd1602初始化函数
* 传入参数: 无
* 返回参数: 无
* 内部变量: 无
* 全局变量: 无
*******************************************************************************/
void Lcd_Init(void)
{
Delays_ms(240);
Delays_ms(240);
Lcd_data |= 0xf0;
Wcom_lcd_8(0x30,0); //三次显示模式设置,不检测忙信号
Delays_ms(20);
Wcom_lcd_8(0x30,0); //三次显示模式设置,不检测忙信号
Delays_ms(20);
Wcom_lcd_8(0x30,0); //三次显示模式设置,不检测忙信号
Delays_ms(20);
Wcom_lcd_8(0x20,0);
Delays_ms(20);
/*
Wcom_lcd(0x28,0);
Delays_ms(5);
Wcom_lcd(0x28,0);
Delays_ms(5);
*/
Wcom_lcd(0x2c,1); //显示模式设置,开始要求每次检测忙信号,4Bit模式
Wcom_lcd(0x08,1); //关闭显示
Wcom_lcd(0x01,1); //显示清屏
Wcom_lcd(0x06,1); // 显示光标移动设置
Wcom_lcd(0x0C,1); // 显示开及光标设置
Wcom_lcd(0x80,1);
Delays_ms(5);
}
/*******************************************************************************
* 函 数 名: main()
* 日 期: 2012年05月06日
* 编 写 人: Lilin
* 函数说明: 主函数
* 传入参数: 无
* 返回参数: 无
* 内部变量: 无
* 全局变量: Wheel_count,Wheel_time,Soft_Id,New_time,Old_time,Cycling_speed,
Mcu_time,
*******************************************************************************/
void main(void)
{
Mcu_Init();
Lcd_Init();
DisplayListChar(1, 0,"0.0km/h");
DisplayListChar(10, 0,"0.0km");
DisplayListChar(0, 1,"00:00:00");
DisplayListChar(9, 1,"Power:0");
while(1);
}
没事,我们已经明白为什么这么难了。
一周热门 更多>