|
因為上次太倉促,這次來真的,原創(chuàng):基于89C51單片機摩爾斯電碼收發(fā)系統(tǒng)仿真,附完整代碼和仿真,還有視頻演示喲。
本人編制此程序僅為興趣和愛好,請大家多多指教和鼓勵。
/*----------------------------------------------------------
* 【實驗平臺】: 89C52單片機開發(fā)板
* 【外部晶振】: 11.0592MHz
* 【主控芯片】: STC89C52
* 【編譯環(huán)境】: Keil μVisio4
* 【程序編寫】: wzqwxx 水上人家
名稱:摩爾斯電碼自動(手動)發(fā)送
內(nèi)容:僅供交流學(xué)習(xí),其他用途請注明編者,若有BUG請原諒編者。
本程序僅實現(xiàn)了短電報自動發(fā)送功能,能用兩個鍵輸入報文,
能用單手鍵發(fā)送報文,或用PC機等終端輸入報文。
編制程序過程本身就很有趣和充滿挑戰(zhàn),要不斷思考修改調(diào)試
完善,從中學(xué)到了不少知識。如果能制作成品,練習(xí)發(fā)報也十分有
趣,這也是對古老的電訊一種紀念,致敬充滿智慧的先輩們。
播發(fā)摩爾斯電碼的一般要求是:以一個“點”的長度為一個時間
單位,“劃”是三個點的時間長度;點劃之間的間隔是一個點的長度;
字符之間的間隔是三個點的長度;單詞之間的間隔是七個點的長度。
這樣才能被收報人識別。
------------------------------------------------------------*/
仿真說明:
1、開機后,出現(xiàn)問候語。即進入信息錄入界面。這時可按點劃鍵進行輸入,這時每輸入一點一劃,都會出現(xiàn)候選字,如是你想要的,可稍停,即可自動上屏。
若不是要連續(xù)輸入,直到找到。字母和數(shù)字可按摩斯碼輸入,空格輸入點點劃劃四筆。 注意,點劃輸入間隔時間不要過長,這個要學(xué)習(xí)適應(yīng)。
2、若輸入出錯,可按菜單鍵一下,出現(xiàn)DEL,按點鍵可刪除一字,按劃鍵全部刪除。
3、在錄入界面下,連按兩下菜單鍵,出現(xiàn)發(fā)送SEND菜單,再按點鍵可發(fā)送。
4、在錄入界面下,連按三下菜單鍵,出現(xiàn)短語phrase菜單,按點劃鍵上下查找,找到短語后,按菜單鍵進入發(fā)送界面,按點鍵發(fā)送。
5、在錄入界面下,連按四下菜單鍵,出現(xiàn)PCINPUT,再按點鍵可進入虛擬終端,點擊終端獲得焦點后,即可輸入字符。按退格鍵刪除一字,按回車發(fā)送,
按ESC返回點劃雙鍵輸入。在終端里,在沒有輸入任何字符下,輸入問號,再輸入數(shù)字,即短語的序號,可調(diào)出短語,按回車發(fā)送。
6、在錄入界面下,按單手鍵可直接純手動發(fā)報。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
MRScode.png (122.15 KB, 下載次數(shù): 95)
下載附件
2021-10-27 22:40 上傳
單片機源程序如下:
- // main.文件
- #include <REGX52.H>
- #include <stdio.H>
- #include "1602.h"
- #include "MRScode.h"
- unsigned char code *HI = "HELLO!";//開機問候語
- void Timer0Init(void) //4毫秒@11.0592MHz
- {
- TMOD &= 0xF0; //設(shè)置定時器模式
- TMOD |= 0x01; //設(shè)置定時器模式
- TL0 = 0x9A; //設(shè)置定時初值
- TH0 = 0xF1; //設(shè)置定時初值
- TF0 = 0; //清除TF0標(biāo)志
- ET0 = 1;
- EA = 1;
- TR0 = 0; //定時器0由點鍵和劃鍵啟動計時
- }
- void UART_init()
- {
- TMOD |= 0x20; //T1工作模式2 8位自動重裝
- TH1 = 0xfd;
- TL1 = 0xfd; //比特率9600 時鐘頻率11.0592MHZ
- TR1 = 1; //啟動T1定時器
- SM0 = 0;
- SM1 = 1; //串口工作方式1 10位異步
- REN = 1; //串口允許接收
- TI = 1;
- }
- /*********按鍵輸入鍵值獲取*******/
- unsigned char keyget()
- {
- unsigned char keyvalue; //鍵值
- beep = Hmove;
- if(Di == 0 ) //點鍵按下
- {
- delay_ms(25);
- if(Di == 0 )
- {
- while(Di == 0 ); //松手檢測
- keyvalue = 1;
- }
- }
- else if(Hu == 0 ) //劃鍵按下
- {
- delay_ms(25);
- if(Hu == 0 )
- {
- while(Hu == 0 );
- keyvalue = 2;
- }
- }
- else if(GL == 0 ) //功能鍵按下
- {
- delay_ms(25);
- if(GL == 0 )
- {
- while(GL == 0 );
- keyvalue = 3;
- }
- }
- else
- {
- keyvalue = 255;
- }
- return(keyvalue);
- }
- void main()
- {
- char i;
- Timer0Init();//初始化定時器0
- UART_init();
- lcd_init();
- Lcdwritestring(0,5,HI);
- for(i = 0; i < 100; i++)
- delay_ms(50);
- send_mrs_code_TEXT(HI); //發(fā)送字符串
- write_com(0x01);// 清屏
- while(1)
- {
- if(~F0) //PSW^5
- keyin(keyget()); //實體鍵輸入
- else
- PCin(); //電腦終端輸入
- };
- }
復(fù)制代碼
- // MRScode.c文件
- #include <stdio.H>
- #include "1602.h"
- #include "MRScode.h"
- unsigned char count; //計算摩爾碼輸入顯示點劃的位置
- unsigned char showbuffer[L]; //顯示緩沖
- unsigned char i = 0; //顯示緩沖數(shù)組下標(biāo)
- static unsigned char time; //按鍵停頓延時計數(shù) 供字符自動上屏
- static unsigned char MODE; //功能切換 MODE=0 KEY輸入,=1按點鍵刪1字,按劃全刪
- //=2按點鍵發(fā)送,=3調(diào)用短語,=4進入PC輸入
- //摩爾斯碼字庫 字母A~Z(下標(biāo)0~25)計26個, 數(shù)字0~9(下標(biāo)26~35)計10個
- // ? , . ! @ : -(下標(biāo)36~42)計7個,總共43個字節(jié)
- unsigned char code MRSZK[] = { 0x61,0X28,0X2a,0x44,0x80,0x22,
- 0x46,0x20,0x60,0x27,0x45,0x24,0x63,0x62,0x47,0x26,0x2d,0x42,
- 0x40,0x81,0x41,0x21,0x43,0x29,0x2b,0x2c,/*A~Z*/0xbf,0xaf,0xa7,
- 0xa3,0xa1,0xa0,0xb0,0xb8,0xbc,0xbe,/*0~9*/0xcc,0xf3,0xd5,0xeb,
- 0xda,0xf8,0xe1/* ?,.!@:- */ };
- unsigned char code ASCIIZK[] = "?,.!@:-"; //符號庫,可擴展
- /*** !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ
- [\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ASCII可見字符 ***/
- //常用短語庫
- unsigned char code *phrase[] = {"ok","NO", "SOS","hello","thank you","receive",
- /*好,不, 求救, 你好, 謝謝你, 收到,*/
- "retransmission","Goodbye", "Help me!", "my location:" , "MAX 10" } ;
- /*重復(fù), 再見, 幫幫我, 我的位置, 最多10條短語*/
- /******不限于這些短語,拋轉(zhuǎn)引玉,其它可視EEPROM大小再添加*****/
- /*********此函數(shù)據(jù)鍵值實現(xiàn)摩斯碼轉(zhuǎn)ASCII碼、并切換菜單實現(xiàn)相關(guān)功能*******/
- void keyin(unsigned char keyvalue)
- {
- static unsigned char MRScode,num;
- unsigned char x,y,z,j;
- bit flag;
- if(keyvalue != 255) //有鍵按下
- {
- Lcdwritestring(1,0," "); // 16空格清第二行
- if(keyvalue == 1) //點鍵
- {
- switch (MODE) //功能模式切換
- {
- case 0: //本機正常輸入點
- TR0 = 1;
- MRScode <<= 1; //發(fā)送端從高位開始的
- Lcdwritechar(1,6+num,'.'); //num為點劃輸入的次數(shù)
- num++;
- break;
- case 1: //按點鍵刪除一字
- MODE = 0;
- if(i > 0) //有字符就刪除
- i--;
- goto CCC;
- case 2: //輸完按點鍵發(fā)送
- MODE = 0;
- send_mrs_code_TEXT(showbuffer);
- goto DDD;
- case 3: //上翻查找調(diào)用短語
- write_com(0x01); //清屏
- for(j= 0;j<L;j++)
- showbuffer[j] = phrase[x][j];
- if(++x > 10)
- x = 10;
- flag = 1;
- goto DDD;
- case 4: //切換到Pc終端輸入
- MODE = 0;
- i = 0;
- F0 = 1;
- Lcdwritestring(1,0,"PC:");
- return;
-
- default:
- MODE = 0;
- return;
- }
- }
- if(keyvalue == 2) //劃鍵
- {
- if(MODE == 1) //按劃鍵全部刪除
- {
- MODE = 0;
- i = 0;
- goto CCC;
- }
- else if(MODE == 3) //下翻查找短語
- {
- write_com(0x01);
- for(j= 0;j<L;j++)
- showbuffer[j] = phrase[x][j];
- if(x>0)
- x--;
- flag = 1;
- goto DDD;
- }
- TR0 = 1; //本機正常輸入劃
- MRScode <<= 1; //發(fā)送端從高位開始的
- MRScode |= 0x01;
- Lcdwritechar(1,6+num,'_');
- num++;
- }
- if(keyvalue == 3 )//功能鍵
- {
- if( ++MODE > 4 ) //循環(huán)顯示菜單
- MODE = 0;
- if(flag == 1) //查找到短語后直接進入發(fā)送菜單
- MODE = 2;
- flag = 0;
-
- switch (MODE) //屏上顯示功能菜單
- {
- case 1:
- write_com(0x01);
- Lcdwritestring(1,13,"DEL"); //刪除
- goto DDD;
-
- case 2:
- write_com(0x01);
- Lcdwritestring(1,8,"SEND->"); //發(fā)送
- goto DDD;
-
- case 3:
- write_com(0x01);
- Lcdwritestring(1,6,"phrase"); // 調(diào)用短語
- goto DDD;
-
- case 4:
- write_com(0x01);
- Lcdwritestring(1,3,"PC IN"); // 進入PC輸入
- goto DDD;
-
- default:
- write_com(0x01);
- Lcdwritestring(1,0,"KEY IN"); // 本機輸入
- goto DDD;
- }
- }
- if(num<5 && num > 0) //處理字母
- {
- if(num == 4 && MRScode == 3) // 輸入 ..-- 是空格
- {
- z = '_'; //顯示用_代替
- goto BBB;
- }
-
- y = (8-3-num) << 5; //得到字母前三位識別碼值
- for(j = 0; j <= 25;j++)//字母字庫地址0~25;
- {
- if( MRSZK[j] == ( MRScode | y) )
- {
- z = j+0x41;//轉(zhuǎn)化成ASCII碼送顯示
- break;
- }
- }
- }
- else if(num>5) //處理符號
- {
- for(j = 36; j <= 42;j++)//符號字庫地址36~42;
- {
- if((MRSZK[j]&0x3F) == MRScode ) //清零高兩位
- {
- z = ASCIIZK[j-36];
- break;
- }
- }
- }
- else //處理數(shù)字
- {
- for(j = 26; j <= 35;j++)//數(shù)字地址26~35;
- {
- if((MRSZK[j]&0x1F) == MRScode ) //清零高三位
- {
- z = j+0x16;
- break;
- }
- }
- }
- Lcdwritechar(1,4,z);//顯示候選字符
- if(num > 5) //滿6個點劃自動上屏
- {
- BBB: time = 0;
- TR0 = 0;
- MRScode = 0;
- num = 0;
- showbuffer[i] = z;//轉(zhuǎn)化成的ASCII碼送顯示
- i++;
- CCC: showbuffer[i] = 0; //字符串結(jié)束加0
- write_com(0x01);
- DDD: Lcdwritestring(0,0,showbuffer);
-
- }
- if(i > L-2)
- {
- Lcdwritestring(1,0,"MEMORY FULL!"); //不能超過顯存最大長度
- showbuffer[i] = 0;//字符串結(jié)束加0
- }
- }
- else
- {
- if( time > 250) //時間到,自動上屏
- {
- goto BBB;
- }
- }
- }
- /*********電腦終端輸入ASCII碼**********/
- void PCin()
- {
- unsigned char j,k,n,Char;
- for(k = 0;k < L;k++)
- showbuffer[k] = 0;//清緩沖
- k = 0;
- do{
- while(!RI);
- RI = 0;
- Char = SBUF; //運行后在仿真終端輸入半角字符
- if(Char == 0x1B) //按ESC鍵退出PC輸入
- {
- write_com(0x01);
- showbuffer[0] = 0;//清緩沖
- Lcdwritestring(0,0,"KEY:");
- F0 = 0; //PSW 用戶位
- MODE = 0;
- return;
- }
- if(Char == 0x08) //按Backspace鍵
- {
- k--; //退格刪除一個字
- if(k == 0xff)
- k = 0 ;
- showbuffer[k] = 0;
- write_com(0x01);// 清屏
- Lcdwritestring(0,0,showbuffer);
- continue;
- }
- showbuffer[k] = Char;
- write_com(0x01);// 清屏
- Lcdwritestring(0,0,showbuffer);
-
- /***此段為輸入短語數(shù)字代碼調(diào)用短語**/
- if(showbuffer[0] == '?') //調(diào)用短語用問號開頭
- {
- if(Char >= '0' && Char <= '9')
- { //如果是數(shù)字
-
- n = n * 10 + (Char-'0'); //轉(zhuǎn)成十進制數(shù)
- if(n>10) //暫時短語只有9個
- {
- n = 10;
- write_com(0x01);
- Lcdwritestring(1,0,phrase[n]);//調(diào)用短語
- for(n = 1;n <= k+1; n++)
- showbuffer[n] = 0;
- Lcdwritestring(0,0,showbuffer);
- n = 0;
- k = 0;
- }
- else
- Lcdwritestring(1,0,phrase[n]);//調(diào)用短語
- }
- }
- k++;
- }while(Char != 0x0D);//回車發(fā)送
- if(showbuffer[0] == '?')
- {
- for(j= 0;j<L;j++)
- showbuffer[j] = phrase[n][j];
- }
- Lcdwritestring(0,0,showbuffer);
- send_mrs_code_TEXT(showbuffer);
- }
- /******此函數(shù)可調(diào)節(jié)整體發(fā)送速度*****/
- void delay_ms(unsigned char date)
- {
- unsigned char i,j;
- for(i = 0;i < date;i++)
- for(j = 0; j < 138; j++);
- } //一點時長138約92ms 188約124.6ms 90約61.5ms
- void S_beep() //1個短滴聲
- { char i;
- for(i=0;i<1;i++)
- {
- beep = 0;
- delay_ms(100);
- beep = 0;
- delay_ms(100);
- }
- beep = 1;
- count++;
- Lcdwritechar(1,9+count,'.');
- }
- void L_beep() //一個長滴音
- { char i;
- for(i=0;i<3;i++)
- {
- beep = 0;
- delay_ms(100);
- beep = 0;
- delay_ms(100);
- }
- beep = 1;
- count++;
- Lcdwritechar(1,9+count,'_');
- }
- void J2_beep() // 間隔2個點靜音
- { char i;
- for(i=0;i<2;i++)
- {
- beep = 1;
- delay_ms(100);
- beep = 1;
- delay_ms(100);
- }
- }
- void J1_beep() // 間隔1個點靜音
- { char i;
- for(i=0;i<1;i++)
- {
- beep = 1;
- delay_ms(100);
- beep = 1;
- delay_ms(100);
- }
- }
- void J4_beep() // 間隔4個點靜音
- { char i;
- for(i=0;i<4;i++)
- {
- beep = 1;
- delay_ms(100);
- beep = 1;
- delay_ms(100);
- }
- }
- /***********發(fā)送一個摩爾斯碼************/
- void MRS_code_send(unsigned char MRS_code )
- {
- unsigned char i; //數(shù)組下標(biāo)
- bit bt; //識別長短聲音
- if(MRS_code < 0x90) //小于是字母
- {
- i = 3 + MRS_code /0x20; //取前三位
- MRS_code <<= i-1;
- for(; i< 8; i++)
- {
- bt = (MRS_code <<= 1)&0x80;
- if(bt)
- L_beep(); //一個長滴音
- else
- S_beep(); //1個短滴聲
- J1_beep(); // 間隔1個點靜音;
- }
- }
- else if(MRS_code > 0x90 && MRS_code < 0xc0) //否則是發(fā)送數(shù)字
- {
- MRS_code <<= 2;
- for(i = 3; i< 8; i++)
- {
- bt = (MRS_code <<= 1)&0x80;
- if(bt)
- L_beep(); //一個長滴音
- else
- S_beep(); //1個短滴聲
- J1_beep(); // 間隔1個點靜音;
- }
- }
- else //否則是發(fā)送符號
- {
- MRS_code <<= 1;
- for(i = 2; i< 8; i++)
- {
- bt = (MRS_code <<= 1)&0x80;
- if(bt)
- L_beep(); //一個長滴音
- else
- S_beep(); //1個短滴聲
- J1_beep(); // 間隔1個點靜音;
- }
- }
- J2_beep(); //字元間隔1+2=3個點靜音
- }
- /******本函數(shù)ASCII碼轉(zhuǎn)摩爾斯碼字符串發(fā)送*****/
- void send_mrs_code_TEXT(unsigned char *p)
- {
- unsigned char i; //i即摩爾斯碼字庫數(shù)組下標(biāo)
- while(*p)
- {
- if(*p != 0x20)//是否是空格
- {
- if(*p >= 0x41 && *p <= 0x5A )//大寫字母A~Z
- {
- i = *p-0x41; //i取字母字庫 ,0x00地址開始
- }
- else if(*p >= 0x61 && *p <= 0x7A) //小寫字母a~z
- {
- i = *p-0x61; //i取字母字庫 ,0x00地址開始 ,
- } //摩斯碼字母不區(qū)分大小寫
- else if(*p >= 0x30 && *p <= 0x39) //數(shù)字0~9
- {
- i = *p-0x16; //i取數(shù)字字庫 ,0x1A地址開始
- }
- else
- {
- switch (*p)
- {
- case '?': i =36; //即字庫數(shù)組下標(biāo)
- break;
- case ',': i =37;
- break;
- case '.': i =38;
- break;
- case '!': i =39;
- break;
- case '@': i =40;
- break;
- case ':': i =41;
- break;
- case '-': i =42;
- break;
- default:goto AAA;//其它字符當(dāng)空格處理
- break;
- }
- }
- count = 0;//清摩爾碼顯示位置
- write_com(0x01);// 清屏
- Lcdwritestring(0,0,p); //第一行顯示待發(fā)字符串
- Lcdwritestring(1,0,"SEND->"); //第二行顯示正在發(fā)送:
- Lcdwritechar(1,8,*p);//第二行顯示待發(fā)字符
- p++;
- MRS_code_send(MRSZK[i]); //發(fā)送一個摩爾碼
- }
- else
- {
- AAA: p++;
- J4_beep(); // 是空格,單詞間隔3+4=7個點靜音
- }
- }
- }
- void time0_MRS (void) interrupt 1 //STC89C52 4毫秒@11.0592MHz
- {
- TL0 = 0x9A; //設(shè)置定時初值 我這是按點平均時長90ms,劃時長270ms設(shè)置的
- TH0 = 0xF1; //設(shè)置定時初值 在接收人工發(fā)送的要設(shè)計智能調(diào)整適應(yīng)
- ++time; //按鍵停頓延時計數(shù) 供字符自動上屏
- }
- ..................................
- 其他,限于篇幅,請在附件里查看。
復(fù)制代碼
51hei.png (11.12 KB, 下載次數(shù): 99)
下載附件
2021-10-27 23:36 上傳
Proteus7.5版本的仿真代碼下載:
摩斯碼104.zip
(371.54 KB, 下載次數(shù): 100)
2021-10-27 22:36 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
仿真演示視頻
https://www.bilibili.com/video/BV15h41187pu?share_source=copy_web
|
評分
-
查看全部評分
|