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