單片機(jī)與PC機(jī)通過(guò)RS232相連,編寫一個(gè)異步串行口通信程序,實(shí)現(xiàn)單片機(jī)與PC機(jī)上的串口助手之間的通信。 功能實(shí)現(xiàn): 1、當(dāng)PC機(jī)向單片機(jī)發(fā)送字符‘1’~‘8’,打開對(duì)應(yīng)的8個(gè)燈; 2、當(dāng)PC機(jī)再次向單片機(jī)發(fā)送字符‘1’~‘8’時(shí),關(guān)閉對(duì)應(yīng)的燈; 3、當(dāng)PC機(jī)向單片機(jī)發(fā)送字符‘d’時(shí),會(huì)在液晶屏上刪除一個(gè)字符; 4、當(dāng)PC機(jī)向單片機(jī)發(fā)送字符‘n’時(shí),會(huì)在液晶屏上換行顯示; 5、當(dāng)PC機(jī)向單片機(jī)發(fā)送字符‘c’時(shí),會(huì)清屏顯示; 6、當(dāng)PC機(jī)向單片機(jī)發(fā)送字符‘m’時(shí),會(huì)打開音樂(lè)播放,結(jié)束后可繼續(xù)操作;
7、當(dāng)PC機(jī)向單片機(jī)發(fā)送其它字符時(shí),會(huì)顯示在1602液晶屏上; 8、當(dāng)矩陣按鍵有按鍵按下時(shí),單片機(jī)會(huì)把鍵值發(fā)送到PC機(jī)上。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
0.png (247.92 KB, 下載次數(shù): 114)
下載附件
2019-2-3 00:07 上傳
單片機(jī)源程序如下:
- #include<reg52.h>
- #include<string.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- uchar str[17];
- uchar ch;
- uchar m,n;
- sbit K1=P3^7;
- bit play=0;
- sbit LEN=P3^4;
- sbit LCDEN=P3^6;
- sbit RS=P3^3;
- sbit RW=P3^5;
- sbit BF=P2^7;
- sbit LED=P0;
- sbit BEEP=P3^2;
- uint I=0,J,K;
- uchar code keyval[]="123456789*0#"; //按鍵對(duì)應(yīng)的符號(hào)
- char s[ ]="MCS-51 Microcomputer";
- uchar OpenLight[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
- uchar CloseLight[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
- uchar code T[49][2]={{0,0},
- {0xF8,0x8B},{0xF8,0xF2},{0xF9,0x5B},{0xF9,0xB7},{0xFA,0x14},{0xFA,0x66},{0xFA,0xB9},{0xFB,0x03},{0xFB,0x4A},{0xFB,0x8F},{0xFB,0xCF},{0xFC,0x0B},
- {0xFC,0x43},{0xFC,0x78},{0xFC,0xAB},{0xFC,0xDB},{0xFD,0x08},{0xFD,0x33},{0xFD,0x5B},{0xFD,0x81},{0xFD,0xA5},{0xFD,0xC7},{0xFD,0xE7},{0xFE,0x05},
- {0xFE,0x21},{0xFE,0x3C},{0xFE,0x55},{0xFE,0x6D},{0xFE,0x84},{0xFE,0x99},{0xFE,0xAD},{0xFE,0xC0},{0xFE,0x02},{0xFE,0xE3},{0xFE,0xF3},{0xFF,0x02},
- {0xFF,0x10},{0xFF,0x1D},{0xFF,0x2A},{0xFF,0x36},{0xFF,0x42},{0xFF,0x4C},{0xFF,0x56},{0xFF,0x60},{0xFF,0x69},{0xFF,0x71},{0xFF,0x79},{0xFF,0x81}
- };
- uchar code music[][2]={
- {0,4},{20,8},{25,4},{22,4},{20,8},
- {20,8},{17,4},{20,4},{22,4},{25,4},
- {20,8},{20,8},{22,8},{20,4},{17,4},
- {15,8},{15,8},{17,8},{20,4},{17,4},
- {15,4},{17,4},{13,8},{22,8},{20,8},
- {22,8},{20,8},{17,8},{22,8},{20,16},
- {20,4},{20,4},{17,4},{15,4},{13,16},
- {13,4},{13,4},{15,4},{17,4},{13,16},
- {0xFF,0xFF}};
- //生日快樂(lè)歌的音符頻率表,不同頻率由不同的延時(shí)來(lái)決定
- uchar code SONG_TONE[]={212,212,190,212,159,169,212,212,190,212,142,159,
- 212,212,106,126,159,169,190,119,119,126,159,142,159,0};
- //生日快樂(lè)歌節(jié)拍表,節(jié)拍決定每個(gè)音符的演奏長(zhǎng)短
- uchar code SONG_LONG[]={9,3,12,12,12,24,9,3,12,12,12,24,
- 9,3,12,12,12,12,12,9,3,12,12,12,24,0};
- void delay(uchar p)
- {
- uchar i,j;
- for(;p>0;p--)
- for(i=181;i>0;i--)
- for(j=181;j>0;j--);
- }
- void DelayMS(uint x)
- {
- uchar t;
- while(x--) for(t=0;t<120;t++);
- }
- //2¥·?oˉêy
- void PlayMusic2()
- {
- // uint i=0,j,k;
- if(SONG_LONG[I]!=0||SONG_TONE[I]!=0)
- {
- for(J=0;J<SONG_LONG[I]*20;J++)
- {
- BEEP=~BEEP;
-
- for(K=0;K<SONG_TONE[I]/3;K++);
- }
- DelayMS(10);
- I++;
- }
- else
- I=0;
- }
- void delay_us(uchar t) //微秒延時(shí)
- {uchar i;
- for(i=0;i<=t;i++);
- }
- void Alarm(uchar t) //報(bào)警
- {
- uchar i,j,k;
- for(j=0;j<t;j++)
- { for(i=0;i<200;i++)
- {BEEP=0;delay_us(50);BEEP=1;delay_us(50);}
- for(k=0;k<100;k++)
- {BEEP=0;delay_us(110);BEEP=1;delay_us(110);}
- }
- }
- void pause()
- {
- uchar i,j;
- for(i=150;i>0;i--)
- for(j=150;j>0;j--);
- }
- void delay_ms(unsigned int xms)
- {
- int i,j;
- for(i=xms;i>0;i--)
- for(j=110;j>0;j--);
- }
- void PlayMusic()
- {
- uchar i=0;
-
- while(1)
- { if(i==40){ ET0=0;
- break; }
- m=music[i][0];
- n=music[i][1];
- if(m==0x00)
- {
- TR0=0;
- delay(n);
- i++;
- }
- else if(m==0xFF)
- {
- TR0=0;
- delay(30);
- i=0;
- }
- else if(m==music[i+1][0])
- {
- TR0=1;
- delay(n);
- TR0=0;
- pause();
- i++;
- }
- else
- {
- TR0=1;
- delay(n);
- i++;
- }
- }
- }
- uchar keypad4_3()//按鍵掃描函數(shù):要去抖,若有按鍵按下,返回對(duì)應(yīng)的按鍵值(0-11),沒(méi)有按鍵按下返回12
- {
- uchar i,row,temp;
- uchar key=12;//按鍵號(hào),初值設(shè)置為12,目的是:沒(méi)有按鍵按下時(shí)返回12;
- //若不設(shè)初值(默認(rèn)值為0),沒(méi)有按鍵按下時(shí),將返回0,會(huì)誤認(rèn)為0被按下
- row=0xef; //從第一行開始
- for(i=0;i<4;i++)
- {
- P1=0xff;
- P1=row; //第i行信號(hào),對(duì)應(yīng)行為低,其他全為高
- row=_crol_(row,1); //生成下一行信號(hào)
- temp=P1; //讀入掃描信號(hào)
- temp=temp&0x07; //屏蔽高5位信號(hào),只保留低3位列信號(hào)
- if(temp!=0x07)//有按鍵被按下,因?yàn)榈趇行某列有按鍵按下,則低3位中有一位為低
- {
- delay_ms(20); //延時(shí)去抖
- temp=P1;
- temp=temp&0x07;
- if(temp!=0x07) //再次確認(rèn)有按鍵被按下
- {
- switch(temp) //根據(jù)低3位列信號(hào),判斷哪個(gè)按鍵被按下
- {
- case 0x06:key=0+3*i;break; //第i行第1列按鍵被按下
- case 0x05:key=1+3*i;break; //第i行第2列按鍵被按下
- case 0x03:key=2+3*i;break; //第i行第3列按鍵被按下
- }
-
- do
- {
- temp=P1; //再次掃描按鍵
- temp=temp&0x07;
- }while(temp!=0x07); //等待按鍵釋放
- }
- }
- }
- return(key);//掃面結(jié)束,返回按鍵值
- }
- uchar RdACAdr()//讀當(dāng)前光標(biāo)地址
- {
- uchar result;
- P2 = 0xff; //讀地址前先置高電平,防止誤判
- RS = 0;
- delay_ms(5);
- RW = 1;
- LCDEN = 1;
- delay_ms(5);
- result=P2&0x7f; //去掉最高位忙閑標(biāo)記,只保留低7位地址值
- LCDEN = 0;
- return result;
- }
- uchar DectectBusyBit(void)//狀態(tài)判斷函數(shù)(忙/閑?)
- {
- bit result;
- P2 = 0xff; //讀狀態(tài)前先置高電平,防止誤判
- RS = 0;
- delay_ms(5);
- RW = 1;
- LCDEN = 1;
- delay_ms(5);
- result=BF; //若LCM忙,則反復(fù)測(cè)試,在此處原地踏步;當(dāng)LCM閑時(shí),才往下繼續(xù)
- LCDEN = 0;
- return result;
- }
- void WrComLCD(unsigned char ComVal)//寫命令函數(shù)
- {
- while(DectectBusyBit()==1); //先檢測(cè)LCM是否空閑
- RS = 0;
- delay_ms(1);
- RW = 0;
- LCDEN = 1;
- P2 = ComVal;
- delay_ms(1);
- LCDEN = 0;
- }
- void WrDatLCD(uchar DatVal)//寫數(shù)據(jù)函數(shù)
- {
- while(DectectBusyBit()==1);
- RS = 1;
- delay_ms(1);
- RW = 0;
- LCDEN = 1;
- P2 = DatVal;
- delay_ms(1);
- LCDEN = 0;
- }
- void WrStrDat(uchar *p)//顯示英文字符串(長(zhǎng)度不超過(guò)32)
- {
- uchar i=0,t;
-
- while(p[i]!='\0')
- {
- WrDatLCD(p[i]);
- i++;
- delay_ms(5);
-
- t=RdACAdr();
- if(t==0x10) WrComLCD(0xc0);//讀當(dāng)前坐標(biāo),如果第1行寫完換行到第2行
- if(t==0x50) WrComLCD(0x80);//讀當(dāng)前坐標(biāo),如果第2行寫完換行到第1行
- }
- }
- void LCD_Init(void)//1602初始化函數(shù)
- {
- //delay(15);
- WrComLCD(0x38);
- //delay(5); // 功能設(shè)定:16*2行、5*7點(diǎn)陣、8位數(shù)據(jù)接口
- WrComLCD(0x38);
- //delay(5);
- WrComLCD(0x38);
- //多次重復(fù)設(shè)定功能指令,因?yàn)長(zhǎng)CD啟動(dòng)后并不知道使用的是4位數(shù)據(jù)接口還是8位的,所以開始時(shí)總是默認(rèn)為4位,這樣剛開始寫入功能設(shè)定指令時(shí),低4位被忽略,為了可靠,最好多寫幾遍該指令
- WrComLCD(0x01); // 清屏
- WrComLCD(0x06); // 光標(biāo)自增、屏幕不動(dòng)
- delay_ms(1); // 延時(shí),等待上面的指令生效,下面再顯示,防止出現(xiàn)亂碼
- WrComLCD(0x0C); // 開顯示、關(guān)光標(biāo)
- }
- void uart_init(unsigned int bps)
- { unsigned char t;
- SCON=0x50; //工作方式一:8位異步收發(fā),波特率可變,允許接收數(shù)據(jù)
- PCON=0x00; //SMOD=0
- TI=0; //軟件清零,表示未發(fā)送完成
- EA=1; //開總中斷
- ET1=1;
- ET0=1; //開T0
- ES=1; //開串口中斷
- TMOD=0x21; //設(shè)置T1定時(shí)器8位自動(dòng)裝載模式
- switch(bps)
- { case 1200:t=0xe8;break;
- case 2400:t=0xf4;break;
- case 4800:t=0xfa;break;
- case 9600:t=0xfd;break;
- }
- TH1=t;
- TL1=t;
- TR1=1; //開啟T1
- }
- void uart_send(unsigned char ch)
- {
- ES=0; //關(guān)串口中斷
- SBUF=ch;
- while(TI==0); //等待發(fā)送完成
- TI=0; //清除中斷標(biāo)記
- ES=1; //開中斷
- }
- unsigned char receive(void)
- { unsigned char dat;
- while(RI==0); //等待接收完畢
- RI=0; //將接收中斷標(biāo)志RI清0,為接收下一幀數(shù)據(jù)做準(zhǔn)備
- dat=SBUF; //將接收緩沖器中的數(shù)據(jù)存入dat
- return dat; //將接收到的數(shù)據(jù)返回
- }
- void main (void)
- { uchar temp=0xff;
- uchar tt=0xff;
- uchar a,b=0;
- uchar keypadVal=12;
- //TMOD=0x21; EA=1; ET0=1;
- //ET1=0;
- //LEN=1;
- PT0=1;
- //PS=1;
- P0=0xff;
- //LEN=0;
- uart_init(9600);//串口初始化
- LCD_Init();//1602液晶屏初始化
- delay_ms(5); //延時(shí),等待初始化完成
- WrComLCD(0x80); //設(shè)置顯示地址第一行第一位:0X00(0x80+0x00)
-
- while(1)
- {
-
- keypadVal=keypad4_3();
- if(keypadVal<12)
- {
- uart_send(keyval[keypadVal]);
- }
- /*if(K1==0)//如按鍵按下,就發(fā)送"MCS-51 Microcomputer"
- {
- b=0;//計(jì)數(shù)器清0
- a=strlen(s);//取數(shù)組長(zhǎng)度
- for(;b<a;b++)//循環(huán)取數(shù)據(jù)發(fā)送,從0到a
- { SBUF=s[b];//發(fā)送"MCS-51 Microcomputer"
- while(!TI);//沒(méi)有發(fā)送完,就等待.
- TI=0;//清發(fā)送結(jié)束標(biāo)志
- }
- while(!K1);//如果按鍵沒(méi)有松開,等待
- }*/
- if(RI||a=='m')//如果接收到數(shù)據(jù),就把接收到的數(shù)回發(fā)給PC
- { uchar pos;
-
- RI=0;//清接收標(biāo)志
-
- //if(a!='m')
- //{
- a=SBUF ;//讀串行口數(shù)據(jù)
- SBUF=a;//把從PC機(jī)發(fā)送過(guò)來(lái)的數(shù)據(jù)返回給PC機(jī)
- // if(a=='m')
- // play=~play;
- // }
-
-
- while(!TI);//沒(méi)有發(fā)送完等待
- TI=0;//清發(fā)送完中斷標(biāo)志
- if(a>'0'&&a<='8')
- {
- if(temp==a)
- tt=tt^(_crol_(0x01,a-'0'-1));
- //P0=0x00;
- else
- tt=tt&(~OpenLight[a-'0'-1]);
- temp=a;
- P0=tt;
- }
- else
- {
- if(a=='n')
- {
- //換行
- pos=RdACAdr();
- if(pos>=0x00&&pos<0x10){ WrComLCD(0xc0);WrStrDat(" ");WrComLCD(0xc0);}//讀當(dāng)前坐標(biāo),如果第1行寫完換行到第2行
- else if(pos>=0x40&&pos<0x50) { WrComLCD(0x80);WrStrDat(" ");WrComLCD(0x80);}//讀當(dāng)前坐標(biāo),如果第2行寫完換行到第1行
- }
- else if(a=='c')
- {
- WrComLCD(0x01);
- WrComLCD(0x80);
- }
- else if(a=='d')
- {
- //刪除
- WrComLCD(0x10);
- WrDatLCD(' ');
- WrComLCD(0x10);
- }
- else if(a=='m')
- { //ET0=1;
- PlayMusic2();
-
- //if(play)
- //Alarm(5);
- }
- else
- {
- WrDatLCD(a);
- //WrComLCD(0x80);
- pos=RdACAdr();
- if(pos==0x10) WrComLCD(0xc0);//讀當(dāng)前坐標(biāo),如果第1行寫完換行到第2行
- if(pos==0x50) WrComLCD(0x80);//讀當(dāng)前坐標(biāo),如果第2行寫完換行到第1行
- }
-
- }
- }
-
- }
- }
- void T0_int() interrupt 1
- {
- BEEP=!BEEP;
- TH0=T[m][0]; TL0=T[m][1];
- }
復(fù)制代碼
所有資料51hei提供下載:
PC機(jī)控制單片機(jī).zip
(259.53 KB, 下載次數(shù): 345)
2019-2-3 00:04 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|