电视频道记忆功能,交通灯倒计时时间的设定,户外 LED 广告的记忆功能,都有可能用到 EEPROM 这类存储器件。这类器件的优势是存储的数据不仅可以改变,而且掉电后数据保存不丢失,因此大量应用在各种电子产品上。
我们这节课的例程,有点类似广告屏。上电后,1602 的第一行显示 EEPROM 从 0x20 地址开始的 16 个字符,第二行显示 EERPOM 从 0x40 开始的 16 个字符。我们可以通过 UART串口通信来改变 EEPROM 内部的这个数据,并且同时也改变了 1602 显示的内容,下次上电的时候,直接会显示我们更新过的内容。
这个程序所有的相关内容,前面都已经讲过了。但是这个程序体现在了一个综合应用能力上。这个程序用到了 1602 液晶、UART 串口通信、EEPROM 读写操作等多个功能的综合应用。写个点亮小灯好简单,但是我们想真正学好单片机,必须得学会这种综合程序的应用,实现多个模块同时参与工作。因此同学们,要认认真真的把工程建立起来,一行一行的把程序编写起来,最终巩固下来。
/*****************************I2C.c 文件程序源代码*******************************/
(此处省略,可参考之前章节的代码)
/***************************Lcd1602.c 文件程序源代码*****************************/
(此处省略,可参考之前章节的代码)
/****************************eeprom.c 文件程序源代码*****************************/
(此处省略,可参考之前章节的代码)
/*****************************Uart.c 文件程序源代码*****************************/
(此处省略,可参考之前章节的代码)
-
- #include <reg52.h>
- unsigned char T0RH = 0;
- unsigned char T0RL = 0;
-
- void InitShowStr();
- void ConfigTimer0(unsigned int ms);
- extern void InitLcd1602();
- extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
- extern void E2Read(unsigned char *buf, unsigned char addr, unsigned char len);
- extern void E2Write(unsigned char *buf, unsigned char addr, unsigned char len);
- extern void UartDriver();
- extern void ConfigUART(unsigned int baud);
- extern void UartRxMonitor(unsigned char ms);
- extern void UartWrite(unsigned char *buf, unsigned char len);
-
- void main(){
- EA = 1;
- ConfigTimer0(1);
- ConfigUART(9600);
- InitLcd1602();
- InitShowStr();
-
- while (1){
- UartDriver();
- }
- }
-
- void InitShowStr(){
- unsigned char str[17];
-
- str[16] = '\0';
- E2Read(str, 0x20, 16);
- LcdShowStr(0, 0, str);
- E2Read(str, 0x40, 16);
- LcdShowStr(0, 1, str);
- }
-
-
-
- bit CmpMemory(unsigned char *ptr1, unsigned char *ptr2, unsigned char len){
- while (len--){
- if (*ptr1++ != *ptr2++){
- return 0;
- }
- }
- return 1;
- }
-
-
- void TrimString16(unsigned char *out, unsigned char *in){
- unsigned char i = 0;
- while (*in != '\0'){
- *out++ = *in++;
- i++;
- if (i >= 16){
- break;
- }
- }
- for ( ; i<16; i++){
- *out++ = ' ';
- }
- *out = '\0';
- }
-
-
- void UartAction(unsigned char *buf, unsigned char len){
- unsigned char i;
- unsigned char str[17];
- unsigned char code cmd0[] = "showstr1 ";
- unsigned char code cmd1[] = "showstr2 ";
-
- unsigned char code cmdLen[] = {
- sizeof(cmd0)-1, sizeof(cmd1)-1,
- };
- unsigned char code *cmdPtr[] = {
- &cmd0[0], &cmd1[0],
- };
- for (i=0; i<sizeof(cmdLen); i++){
- if (len >= cmdLen[i]){
- if (CmpMemory(buf, cmdPtr[i], cmdLen[i])){
- break;
- }
- }
- }
- switch (i){
- case 0:
- buf[len] = '\0';
- TrimString16(str, buf+cmdLen[0]);
- LcdShowStr(0, 0, str);
- E2Write(str, 0x20, sizeof(str));
- break;
- case 1:
- buf[len] = '\0';
- TrimString16(str, buf+cmdLen[1]);
- LcdShowStr(0, 1, str);
- E2Write(str, 0x40, sizeof(str));
- break;
- default:
- UartWrite("bad command.\r\n", sizeof("bad command.\r\n")-1);
- return;
- }
- buf[len++] = '\r';
- buf[len++] = '\n';
- UartWrite(buf, len);
- }
-
- void ConfigTimer0(unsigned int ms){
- unsigned long tmp;
- tmp = 11059200 / 12;
- tmp = (tmp * ms) / 1000;
- tmp = 65536 - tmp;
- tmp = tmp + 33;
-
- T0RH = (unsigned char)(tmp>>8);
- T0RL = (unsigned char)tmp;
- TMOD &= 0xF0;
- TMOD |= 0x01;
- TH0 = T0RH;
- TL0 = T0RL;
- ET0 = 1;
- TR0 = 1;
- }
-
- void InterruptTimer0() interrupt 1{
- TH0 = T0RH;
- TL0 = T0RL;
- UartRxMonitor(1);
- }
我们在学习 UART 通信的时候,刚开始也是用的 IO 口去模拟 UART 通信过程,最终实现和电脑的通信,而后因为 STC89C52 内部具备 UART 硬件通信模块,所以我们直接可以通过配置寄存器就可以很轻松的实现单片机的 UART 通信。同样的道理,这个 I2C 通信,如果单片机内部有硬件模块的话,单片机可以直接自动实现 I2C 通信了,就不需要我们再进行 IO口模拟起始、模拟发送、模拟结束,配置好寄存器,单片机就会把这些工作全部做了。
不过我们的 STC89C52 单片机内部不具备 I2C 的硬件模块,所以我们使用 STC89C52 进行 I2C 通信的话必须用 IO 口来模拟。使用 IO 口模拟 I2C 实际上更有利于我们彻底理解透彻 I2C 通信的实质。当然了,通过学习 IO 口模拟通信,今后如果遇到内部带 I2C 模块的单片机,也应该很轻松的搞定,使用内部的硬件模块,可以提高程序的执行效率。