产生:
单片机能不能做出一些高级有好van的东西呢?答案当然是可以,这次用单片机模拟的短信接收装置个人感觉比较不错,所以就拿出来分享了。
简介:
使用的板子是"STC89C52",用到的核心模块是LCD1602和AT24C02模块,短信的输入和发送用到串口通信,矩阵键盘用来决定短信存储的位置和一系列对短信的操作。
具体功能:
使用串口发送字符串模拟短信内容的发送,之后通过LCD1602进行短信内容的显示模拟短信的接收,通过AT24C02实现短信的储存,删除,读取条数等功能。每条短信上限为32个字节,最多储存8条短信(AT24C02储存地址有限)。收到的短信可以储存在任意已初始化后的地址,可以对短信进行储存,对任意储存短信进行删除和读取,随时可以得到已经储存短信的条数。
按键示意图:
0——1——2——3
4——5——6——7
IM——IM——IM——IM
IM——IM——W——R
SH——S——G——D
(IM=空闲键,W=储存短信条数键,R=显示短信条数键,SH=显示短信内容键,S=储存短信内容键,G=读取短信内容键,D=删除短信内容键)
按键操作时序:
烧录完成后:
串口发送->0-7按键任意按下一个->按下S键->按下G键->按下SH键
(操作完一次后可看到LCD1602上显示出短信内容,可以重复操作,但每次0-7按键值需要不一样,表示不同的地址储存不同的短信)
如果要删除短信,在进行至少一次上述操作后,先按下0-7中的一个键,再按下D键,就完成了删除。在全部操作完成后,先按下W键,再按下R键即可显示出储存的短信条数(不包含已经被删除的短信)
掉电复位后:
如果要读取短信,先按下0-7中的任意一个,接着按G键,然后按SH键即可(如果没有内容表示短信已被删除或者根本没有向该地址内写入短信)如果要查看已经储存的条数,直接按R键就好了。如果要再次保存或者删除短信,按照烧录完成后的操作进行就好了
源代码:
//模拟短信接收系统
//通过串口发送短信内容,然后通过LCD1602显示
//可以保存,删除,显示任意一条短信(上限为8条,每条32字节)
//对短信内容有掉电保护功能
//可以显示目前已储存的短信条数
//按键分布:
//0 1 2 3
//4 5 6 7
//IM IM IM IM
//IM IM W R
//SH S G D
//IM=空闲键,W=保存当前条数键,R=显示短信条数键,SH=显示短信内容键
//S=短信储存键,G=短信读取键,D为短信删除键
#include <reg52.h>
#include <intrins.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit SDA=P2^0;
sbit SCL=P2^1;
sbit Beep=P2^3;
sbit RS=P3^5;
sbit RW=P3^6;
sbit EN=P3^4;
uchar i=0;//串口接收字符串变量
uchar x=0;//字符串数组长度
uchar a=0;//短信储存地址变量
uchar num=0;//短信条数
uchar tabel1[32];//用于接收串口传输过来的字符串
uchar tabel2[32];//用于储存从AT24C02中读取出来的字符串
uchar tabel3[8]={0x00,0x20,0x40,0x60,0x80,0xa0,0xc0,0xe0};//用于储存字符串储存的地址
uchar tabel4[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};//LCD1602显示地址
/********串口通信********/
void UARTInit()//串口的初始化
{
TMOD|=0X20;
TH1=0XFD;
TL1=0XFD;
TR1=1;
SM0=0;
SM1=1;
REN=1;
EA=1;
ES=1;
}
void UART() interrupt 4
{
uchar temp;
if(RI)
{
temp=SBUF;
RI=0;
if(temp!='\0')
{
tabel1[i]=temp;
i++;
}
}
}
/********LCD1602********/
void Read_Busy()
{
uchar busy;
P0=0XFF;
RS=0;
RW=1;
do
{
EN=1;
busy=P0;
EN=0;
}while(busy&0x80);
}
void Write_cmd(uchar cmd)
{
Read_Busy();
RS=0;
RW=0;
P0=cmd;
EN=1;
EN=0;
RS=1;
RW=1;
EN=1;
}
void Write_dat(uchar dat)
{
Read_Busy();
RS=1;
RW=0;
P0=dat;
EN=1;
EN=0;
RS=1;
RW=1;
EN=1;
}
void LCD1602Init()
{
Write_cmd(0x38);
Write_cmd(0x0c);
Write_cmd(0x01);
}
void LCDWrite()
{
x=0;
Write_cmd(0x01);
while(x<16)
{
Write_cmd(tabel4[x]|0x80);
Write_dat(tabel2[x]);
x++;
}
while((x>=16)&&(x<32))
{
Write_cmd((tabel4[x-16]+0x40)|0x80);
Write_dat(tabel2[x]);
x++;
}
}
void LCDNum()
{
Write_cmd(0x01);
Write_cmd(0x00|0x80);
Write_dat((num+'0'));
}
/********IIC********/
void delay_10us()
{
_nop_();
_nop_();
}
void delay_write(uint a)
{
uint b;
for(b=0;b<a;b++);
}
void Init()
{
SCL=1;
delay_10us();
SDA=1;
delay_10us();
}
void Start()
{
SDA=1;
delay_10us();
SCL=1;
delay_10us();
SDA=0;
delay_10us();
SCL=0;
delay_10us();
}
void Stop()
{
SDA=0;
delay_10us();
SCL=1;
delay_10us();
SDA=1;
delay_10us();
}
void Writebyte(uchar a)
{
uchar b,temp;
temp=a;
for (b=0;b<8;b++)
{
temp=temp<<1;
SCL=0;
delay_10us();
SDA=CY;
delay_10us();
SCL=1;
delay_10us();
}
SCL=0;
delay_10us();
SDA=1;
delay_10us();
}
uchar Readbyte()
{
uchar i,j,k=0;
SCL=0;
delay_10us();
SDA=1;
for (i=0;i<8;i++)
{
delay_10us();
SCL=1;
delay_10us();
if(SDA==1)
j=1;
else
j=0;
k=(k<<1)|j;
SCL=0;
}
delay_10us();
return k;
}
void ACK()
{
uchar i=0;
SCL=1;
delay_10us();
while((SDA==1)&&(i<255))
i++;
SCL=0;
delay_10us();
}
uchar ReadAT24C02(uchar ADDR)
{
uchar i;
Start();
Writebyte(0xa0);
ACK();
Writebyte(ADDR);
ACK();
Start();
Writebyte(0xa1);
ACK();
i=Readbyte();
Stop();
delay_write(100);
return i;
}
void WriteAT24C02(uchar ADDR,uchar DATA)
{
Start();
Writebyte(0xa0);
ACK();
Writebyte(ADDR);
ACK();
Writebyte(DATA);
ACK();
Stop();
delay_write(500);
}
/********数据处理********/
void Show_information()
{
LCDWrite();
}
void Save_information(uchar a)
{
x=0;
while(x<32)
{
WriteAT24C02(tabel3[a]+x,tabel1[x]);
tabel1[x]=0x20;
x++;
}
num++;
i=0;
}
void Get_information(uchar a)
{
x=0;
while(x<32)
{
tabel2[x]=ReadAT24C02(tabel3[a]+x);
x++;
}
}
void Delete_information(uchar a)
{
x=0;
while(x<32)
{
WriteAT24C02(tabel3[a]+x,0X20);
x++;
}
num--;
}
/********独立键盘********/
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=114;y>0;y--);
}
void keyscan()
{
P3=0XFF;
if(P3==0XFE)//显示键
{
delay(20);
if(P3==0XFE)
{
Show_information();
Beep=0;
while(P3==0XFE);
}
Beep=1;
}
P3=0XFF;
if(P3==0XFD)//储存键
{
delay(20);
if(P3==0XFD)
{
Save_information(a);
Beep=0;
while(P3==0XFD);
}
Beep=1;
}
P3=0XFF;
if(P3==0XFB)//读取键
{
delay(20);
if(P3==0XFB)
{
Get_information(a);
Beep=0;
while(P3==0XFB);
}
Beep=1;
}
P3=0XFF;
if(P3==0XF7)//删除键
{
delay(20);
if(P3==0XF7)
{
Delete_information(a);
Beep=0;
while(P3==0XF7);
}
Beep=1;
}
}
/********矩阵键盘********/
void keyscan1()
{
uchar temp;
P3=0XFF;
P3=0XFE;
temp=P3&0XF0;
if(temp!=0xf0)
{
delay(20);
P3=0XFE;
temp=0xf0&P3;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xee:a=0;Beep=0;break;
case 0xde:a=1;Beep=0;break;
case 0xbe:a=2;Beep=0;break;
case 0x7e:a=3;Beep=0;break;
}
while(temp!=0xf0)
{
temp=P3&0XF0;
}
Beep=1;
}
}
P3=0XFF;
P3=0XFd;
temp=P3&0XF0;
if(temp!=0xf0)
{
delay(20);
P3=0XFd;
temp=0xf0&P3;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xed:a=4;Beep=0;break;
case 0xdd:a=5;Beep=0;break;
case 0xbd:a=6;Beep=0;break;
case 0x7d:a=7;Beep=0;break;
}
while(temp!=0xf0)
{
temp=P3&0XF0;
}
Beep=1;
}
}
P3=0XFF;
P3=0XFb;
temp=P3&0XF0;
if(temp!=0xf0)
{
delay(20);
P3=0XFb;
temp=0xf0&P3;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xeb:break;
case 0xdb:break;
case 0xbb:break;
case 0x7b:break;
}
while(temp!=0xf0)
{
temp=P3&0XF0;
}
Beep=1;
}
}
P3=0XFF;
P3=0XF7;
temp=P3&0XF0;
if(temp!=0xf0)
{
delay(20);
P3=0XF7;
temp=0xf0&P3;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xe7:break;
case 0xd7:break;
case 0xb7:Beep=0;WriteAT24C02(0xa0,num);break;
case 0x77:Beep=0;num=ReadAT24C02(0Xa0);LCDNum();break;
}
while(temp!=0xf0)
{
temp=P3&0XF0;
}
Beep=1;
}
}
P3=0XFF;
}
/********main函数********/
void main()
{
uchar i;
UARTInit();
Init();
LCD1602Init();
for(i=0;i<32;i++)
{
tabel1[i]=0x20;
tabel2[i]=0x20;
}
while(1)
{
keyscan();
keyscan1();
}
}
P.S.
1、烧录前将keil中晶振调为11.0592MHZ,Model选DATA,本人调试过后这样显示是比较稳定的。
2、由于本人水平有限,代码可能会有一些冗余,欢迎各位大神提出意见,看到后我会尽力精简的~
3、看到这里的小可爱别忘了点个赞支持一下哈~