本文章是我在实验课上所完成的一项基于 51 单片机的 RFID 仿真高速收费系统,前前后后花费了快一个月的时间,彻底搞懂了AMPIRE128X64这块液晶显示屏,才开发出了这套系统,电路图虽然简单,但是后面的程序却花费了很长时间去弄,只能说嵌入式这行工作,单靠理论是完全不够的,你还要去接触新的东西,边学边用,多学多用,才能将要领熟记于心,废话不多说,让我们开始这项系统之旅!
先看看完整的电路图和所使用的元器件:


可以看到,所使用的元器件很少,这里最难的部分就是LED显示器的驱动代码,玩好这块LCD显示屏,你就知道有多爽了(狗头)。
一、基本要求
先看看这个系统实现的基本功能要求 :
1. 系统初始化显示
程序启动,液晶屏初始化完成后,显示 “欢迎您”。

2. 车辆刷卡模拟
设置两个按钮,分别模拟小车和货车的 RFID 刷卡动作。首次刷卡表示车辆进
入高速,再次刷卡表示车辆离开高速,后续刷卡依此规律循环。
3. 车辆进入高速状态显示
•
车辆进入高速后开始计时。液晶屏清空后,以清晰格式显示信息:第一行显示 “Time: [进入高速时长(分钟)]”;第二行显示 “Type:
[车辆类型(C 表示小车,T 表示货车)] Fee: [应扣金额(元)]”。

•
车辆离开高速,计时停止,液晶屏清空后显示 “Total Fee: [总费用(元)]” 和 “Total Time: [总时长(分钟)]”。

4. 参数设置功能
•
设置按钮
:用于循环设置小车和货车的每分钟收费价格及进入高速的最长时间。每次按下,按小车收费价格、货车收费价格、小车最长时间、
货车最长时间的顺序依次设置。按下时,液晶屏清空并显示对应设置项
及当前值,如 “car price: [单价(元 / 分钟)]”、“truck
price: [单价(元 / 分钟)]”、“car MaxTime: [最长时间(分钟)]”、“truck MaxTime: [最长时间(分钟)]”。




•
加按钮
:在设置状态下,按下一次可将当前设置项的值增加 1(收费价格增加 1 元 / 分钟,最长时间增加 1 分钟)。
•
减按钮
:在设置状态下,按下一次可将当前设置项的值减少 1(收费价格减少 1 元 / 分钟,最长时间减少 1 分钟)。收费价格范围为 1 -
10 元 / 分钟。
5. 超时报警功能
•
若车辆在高速上的时长超过设置的最长时间且仍未离开,LED 亮起,蜂鸣器发出警报。
•
报警期间,计时和费用计算正常进行,液晶屏持续显示计时和应付费用。

•
车辆离开高速或未达到最长时间,蜂鸣器停止报警。
6. 按钮操作限制
•
车辆在高速行驶期间,设置按钮、加按钮和减按钮操作无效。
•
按下小车或货车按钮,设置命令结束,液晶屏对应设置显示内容清除。
•
车辆进入高速后,需待其离开高速,设置按钮方可再次使用。
二、功能代码
在此之前,有必要先说明一下我的中文字模取模软件:PCtoLCD2002,设置界面如下:
其他取模软件也可以,输出“欢迎您”这三个字的字符跟我一样应该就没问题:
接下来是对各个共能代码的拆分和分析:
1. 系统初始化显示
程序启动,液晶屏初始化完成后,显示 “欢迎您”。
uchar code Welcome[]={
0x04,0x24,0x44,0x84,0x64,0x9C,0x40,0x30,0x0F,0xC8,0x08,0x08,0x28,0x18,0x00,0x00,
0x10,0x08,0x06,0x01,0x82,0x4C,0x20,0x18,0x06,0x01,0x06,0x18,0x20,0x40,0x80,0x00,/*"欢",0*/
0x40,0x40,0x42,0xCC,0x00,0x00,0xFC,0x04,0x02,0x00,0xFC,0x04,0x04,0xFC,0x00,0x00,
0x00,0x40,0x20,0x1F,0x20,0x40,0x4F,0x44,0x42,0x40,0x7F,0x42,0x44,0x43,0x40,0x00,/*"迎",1*/
0x20,0x10,0x08,0xFC,0x23,0x10,0x88,0x67,0x04,0xF4,0x04,0x24,0x54,0x8C,0x00,0x00,
0x40,0x30,0x00,0x77,0x80,0x81,0x88,0xB2,0x84,0x83,0x80,0xE0,0x00,0x11,0x60,0x00,/*"您",2*/
};
void Hz_Left_Disp(uint line,uint str,uchar page,uchar column, uchar code *Bmp) {
uint hline=0;
uchar j=0,i=0,lie=0;
for(hline=0;hline<line;hline++){
for(j=0;j<2;j++){
write_com(Page_Add+page+j);
write_com(LCDCol_Add+column+lie);
for(i=0;i<16;i++)
write_data(Bmp[str+i]);
str+=16;
}
lie+=16;
}
}
void Hz_Right_Disp(uint line,uint str,uchar page,uchar column, uchar code *Bmp) {
uint hline=0;
unsigned char j=0,i=0,lie=0;
for(hline=0;hline<line;hline++){
for(j=0;j<2;j++) {
write_com(Page_Add+page+j);
write_com(LCDCol_Add+column+lie);
for(i=0;i<16;i++)
write_data(Bmp[str+i]);
str+=16;
}
lie+=16;
}
}
void WelcomeLCD(){
init_lcd();
Clr_Scr();
LCDMcs=0;
LCDScs=1;
Hz_Left_Disp(2,0,0,32,Welcome);
LCDMcs=1;
LCDScs=0;
Hz_Right_Disp(1,64,0,0,Welcome);
}
其实Hz_Right_Disp和Hz_Left_Disp函数是完全一样的,只是这里为了区分,才写成这个样子的

可以看到,在welcome这个数组里,储存了欢迎您这三个字的字模,通过开启和关闭左右半屏,实现了液晶显示器的初始界面。
Hz_Right_Disp(1,64,0,0,Welcome);这个函数的传入分别是
Hz_Right_Disp(显示的字中文数,数组的起始位置,显示行数,其实页,数组名);
(tips:形参的英文可能有问题,麻烦以实物为主,因为主包英文不太好)
这个函数以及封装好了,可以当作中文的显示函数,大家可以直接拿去用,关于write_com和write_data两个函数下面会给到,就是两个LCD的驱动函数。
2. 车辆刷卡模拟
设置两个按钮,分别模拟小车和货车的 RFID 刷卡动作。首次刷卡表示车辆进
入高速,再次刷卡表示车辆离开高速,后续刷卡依此规律循环。
3. 车辆进入高速状态显示
•
车辆进入高速后开始计时。液晶屏清空后,以清晰格式显示信息:第一行显示 “Time: [进入高速时长(分钟)]”;第二行显示 “Type:
[车辆类型(C 表示小车,T 表示货车)] Fee: [应扣金额(元)]”。
•
车辆离开高速,计时停止,液晶屏清空后显示 “Total Fee: [总费用(元)]” 和 “Total Time: [总时长(分钟)]”。
这段代码有点长,我把注释都放在代码里面,方便大家观看:
uchar code number[][16]={//数字字模数组
// 1(0) 2(1) 3(2) 4(3) 5(4) 6(5) 7(6) 8(7) 9(8) 0(9)
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00},/*"0"*/
{0x00,0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00},/*"1"*/
{0x00,0x70,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},/*"2"*/
{0x00,0x30,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x18,0x20,0x21,0x21,0x22,0x1C,0x00},/*"3"*/
{0x00,0x00,0x80,0x40,0x30,0xF8,0x00,0x00,0x00,0x06,0x05,0x24,0x24,0x3F,0x24,0x24},/*"4"*/
{0x00,0xF8,0x88,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x20,0x20,0x20,0x11,0x0E,0x00},/*"5"*/
{0x00,0xE0,0x10,0x88,0x88,0x90,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x20,0x1F,0x00},/*"6"*/
{0x00,0x18,0x08,0x08,0x88,0x68,0x18,0x00,0x00,0x00,0x00,0x3E,0x01,0x00,0x00,0x00},/*"7"*/
{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00},/*"8"*/
{0x00,0xF0,0x08,0x08,0x08,0x10,0xE0,0x00,0x00,0x01,0x12,0x22,0x22,0x11,0x0F,0x00},/*"9"*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*enmpty,10*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*enmpty,10*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*enmpty,10*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*enmpty,10*/
};
uchar code time_type_fee[]={//主界面字符字模
// T(0) i(1) m(2) e(3) :(4)
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,/*"T",0*/
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,/*"i",1*/
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,/*"m",2*/
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x24,0x24,0x24,0x24,0x17,0x00,/*"e",3*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x36,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*":",0*/
//分(0) 钟(1)
0x80,0x40,0x20,0x90,0x88,0x86,0x80,0x80,0x80,0x83,0x8C,0x10,0x20,0x40,0x80,0x00,
0x00,0x80,0x40,0x20,0x18,0x07,0x00,0x40,0x80,0x40,0x3F,0x00,0x00,0x00,0x00,0x00,/*"分",0*/
0x20,0x10,0x2C,0xE7,0x24,0x24,0x00,0xF0,0x10,0x10,0xFF,0x10,0x10,0xF0,0x00,0x00,
0x01,0x01,0x01,0x7F,0x21,0x11,0x00,0x07,0x02,0x02,0xFF,0x02,0x02,0x07,0x00,0x00,/*"钟",1*/
// T(0) y(1) p(2) e(3) :(4)
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,/*"T",0*/
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x81,0x86,0x78,0x18,0x06,0