论坛风格切换切换到宽版
  • 14132阅读
  • 39回复

写个简单的自动键程序! [复制链接]

上一主题 下一主题
离线Iraqi
 
发帖
393
只看楼主 倒序阅读 0楼 发表于: 2008-01-26
用89c51单片机实现的,能用1602显示拍发的点和划,有点划记忆功能,边发边听!
离线Iraqi
发帖
393
只看该作者 1楼 发表于: 2008-01-26
#include <regx51.h>
#define queue_size 6      //定义自动键的缓存队列长度。
#define cw_tone_frequency      800      //定义侧音频率。可定义成变量,在程序中进行设置,本程序忽略。

/* ************************************************************** */
//1、以点为基本单位,1个划的长度=3点的长度,点的长度可调整,划的长度由程序控制。
//2、在1个字母或数字内,各点、划之间的间隔为1个点的长度,该间隔由程序控制。
//3、字母(数字)与字母(数字)之间的间隔为3点的长度,该长度拍发时人工控制。
/* ************************************************************** */
/* ************************************************************** */
unsigned char dot_dash_buffer[queue_size];      //定义数组作为自动键的缓存队列
unsigned char dot_dash_buffer_head=queue_size-1;      //循环数组实现队列,定义队列头
unsigned char dot_dash_buffer_tail=queue_size-1;      //循环数组实现队列,定义队列尾
/* ************************************************************** */

/*      在程序中通过按键输入可对该变量进行重新设置,从而调整发码速度。      */
unsigned int dot_time=10;      //本程序按每分钟12个word(paris)固定设置:1个点的时间约为100ms.
/*      *********************************************************** */
/* 定义电键的输入端,增加程序的可读性和电路的可移植性 */
sbit paddle_dot=p3^7;
sbit paddle_dash=p3^6;
     
/* 定义电键的输出端,增加程序的可读性和电路的可移植性 */
sbit cw_out=p3^5;      //cw输出,接晶体管开关电路
sbit cw_tone_out=p3^4;      //侧音电路,接晶体管开关电路
/*      *********************************************************** */

/* 定义点和划的状态寄存器,记忆上一次paddle_dot和paddle_dash的状态 */
bit      paddle_dot_register;
bit      paddle_dash_register;

/*      *********************************************************** */

/*      每次t0/c0中断发生时dot_dash_timer、clear_lcd自动加1,方便程序计时      */
unsigned char dot_dash_timer;
unsigned int clear_lcd;

/*      每次t0/c0中断发生时dot_duration、dash_duration自动减1,方便程序计时      */
unsigned char dot_duration;
unsigned char dash_duration;

/*      发划函数 */
void send_dash(void)
{
dot_dash_timer=0;
cw_out=1;

/*      开定时器1,音频开      */
tr1=1;

while(dot_dash_timer!=3*dot_time);//等待dash的时间到
cw_out=0;
/*      关定时器,音频关      */
tr1=0;
cw_tone_out=0;

while(dot_dash_timer!=4*dot_time);//等待间隔时间到

}
/*      *********************************************************** */

void send_dot(void)
{
dot_dash_timer=0;
cw_out=1;

/*      开定时器,音频开      */
tr1=1;

while(dot_dash_timer!=dot_time);//等待达的时间到
cw_out=0;
/*      关定时器,音频关      */
tr1=0;
cw_tone_out=0;

while(dot_dash_timer!=2*dot_time);//等待间隔时间到

}

/*      *********************************************************** */
/*      定义时钟中断,使用t/c0时钟      */

void timer_0(void)interrupt 1 using 1
{
//      每次中断软计时器加1      
dot_dash_timer++;
clear_lcd++;

/* 如果电键按下,将点划"0"、"1"入缓存队列*/
if(paddle_dot==0)
     {
     
     if (paddle_dot_register==0)
           {      //常按paddle_dot
           if(dot_duration--==0)      paddle_dot_register=1;
           }
     else      //每次按后放开paddle_dot
           {
           /*队列不满,则入队列;队尾下标要加1,本程序假定队列永远不满      */
           dot_dash_buffer_tail= (dot_dash_buffer_tail+1)%queue_size;
           dot_dash_buffer[dot_dash_buffer_tail]=0;
                 
           paddle_dot_register=paddle_dot;
           dot_duration=2*dot_time;      //时间间隔可根据手感调整
           }
     }
else      paddle_dot_register=paddle_dot;

if(paddle_dash==0)
     {
     
     if (paddle_dash_register==0)
           {      //常按paddle_dash
           if(dash_duration--==0)      paddle_dash_register=1;
           }
     else      //每次按后放开paddle_dash
           {
           /*队列不满,则入队列;队尾下标要加1,本程序假定队列永远不满      */
           dot_dash_buffer_tail= (dot_dash_buffer_tail+1)%queue_size;
           dot_dash_buffer[dot_dash_buffer_tail]=1;
                 
           paddle_dash_register=paddle_dash;
           dash_duration=4*dot_time;      //时间间隔可根据手感调整
           }
     }
else      paddle_dash_register=paddle_dash;

/*      本程序每10ms中断一次      */
th0=-(10000/256);      //初值取整,赋值th0
tl0=-(10000%256);      //初值取余,赋值tl0
}

/*      定义时钟中断,使用t/c1时钟      */
void timer_1(void)interrupt 3 using 2
{      
cw_tone_out=!cw_tone_out;
/*      音频频率可调,本程序每0.666ms中断一次,频率750hz      */
th1=-(cw_tone_frequency/256);      //初值取整,赋值th0
tl1=-(cw_tone_frequency%256);      //初值取余,赋值tl0
}


/*      ***********************lcd_1602显示相关函数*********************      */
extern bit lcd_1602_check_bf();      
extern void lcd_1602_write_command(unsigned char command);
extern void lcd_1602_write_character(unsigned char character);
//extern void int_to_string(unsigned char *buffer,unsigned int i);
extern void lcd_1602_display_string(unsigned char position,unsigned char *string);
/*      *****************************************************************      */

main(void)
{

/* 初始化输入端口,使其工作在输入状态 */
paddle_dot=1;
paddle_dash=1;

paddle_dot_register=paddle_dot;
paddle_dash_register=paddle_dash;

/* 初始化输出端口,使其工作在输出状态 */
cw_out=0;
cw_tone_out=0;

dot_dash_timer=0;
clear_lcd=0;
/*      ************************************************************************      */
/*      初始化lcd,显示初始值。      */
/*      ************************************************************************      */

lcd_1602_write_command(0x38);      //0x38表示:8位数据、2行显示、5×8点阵
lcd_1602_write_command(0x0c);      //0x0c表示:显示开,光标关,不闪烁
lcd_1602_write_command(0x06);      //ac自动加1

lcd_1602_display_string(0x00|0x80,"cw player 12wpm");
lcd_1602_display_string(0x40|0x80,"750hz");

lcd_1602_write_command(0x48 | 0x80);

/* ************************************************************************            */
/* t/c0&1工作在定时器方式1 */
tmod=0x11;
/* 计数器预置初值,计时器的计数率为fosc/12,当单片机的fosc=12mhz时,机器周期为1us.当计数器
工作在方式1时,设置初值的计算公式为:(2的16次方-计数初值)*1us=定时间隔数, */
/*      本程序t/c0每10ms中断一次      */
th0=-(10000/256);      //初值取整,赋值th0
tl0=-(10000%256);      //初值取余,赋值tl0

/*      音频频率可调,本程序每0.666ms中断一次,频率750hz      */
th1=-(cw_tone_frequency/256);      //初值取整,赋值th1
tl1=-(cw_tone_frequency%256);      //初值取余,赋值tl1
/* cpu开中断 */
ea=1;
/* t/c0&1开中断 */
et0=1;
et1=1;
/*      开定时器0      */
tr0=1;
/* ************************************************************************            */
while(1)
     {
     
     /*      自动键输入缓冲区如果不空,则发送缓冲区中的点或划。*/
     /*      缓冲区的头指针和尾指针相等时,则判定缓冲区为空      */
     if (dot_dash_buffer_head!=dot_dash_buffer_tail)
           {
           /*      如果上一个码发完则清屏,为下一次显示做准备,判断条件为大于3个点的时间内没有发码, */            
           if (clear_lcd>3*dot_time)
                 {
                 lcd_1602_display_string(0x48 | 0x80,"     ");
                 lcd_1602_write_command(0x48 | 0x80);
                 }
           /*      *********************************************      */
           switch (dot_dash_buffer[(dot_dash_buffer_head+1)%queue_size])
                 {
                 case 0:
                       {
                       send_dot();                  
                       lcd_1602_write_character('.');
                       break;
                       }
                 case 1:      
                       {
                       send_dash();                              
                       lcd_1602_write_character('_');
                       break;
                       }
                  }
           
           /*      缓冲区队首指针后移,已发完的点或划出队列      */
           dot_dash_buffer_head = (dot_dash_buffer_head+1)%queue_size;
           
           /*      对发完后的时间间隔开始计时      */
           clear_lcd=0;
           }
     
     }

}
离线Iraqi
发帖
393
只看该作者 2楼 发表于: 2008-01-26
//1602采用标准的14脚接口,其中:

//第1脚:vss为地电源

//第2脚:vdd接5v正电源

/*第3脚:v0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,
对比度过高时会产生“鬼影”,使用时可以通过一个10k的电位器调整对比度*/

//第4脚:rs为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。

//第5脚:r/w为读写信号线,高电平时进行读操作,低电平时进行写操作。

//当rs和r/w共同为低电平时可以写入指令或者显示地址,
//当rs为低电平,r/w为高电平时可以读忙信号,
//当rs为高电平,r/w为低电平时可以写入数据。

//第6脚:e端为使能端,当e端由高电平跳变成低电平时,液晶模块执行命令。

//第7~14脚:d0~d7为8位双向数据线。
//另外引脚"a"和"k"为背光引脚,"a"接正,"k"接负便会点亮背光灯。

#include <regx51.h>

/*      ****************************************************************************      */
/*      定义lcd的引脚与单片机的io引脚对应,程序中不在体现io引脚,这样程序可移植性较强      */

//* 定义 db=p2      */

sfr            db      = 0xa0;      

/* 定义      p2_0=db0      p2_1=db1      p2_2=db2      p2_3=db3      
           p2_4=db4      p2_5=db5      p2_6=db6      p2_7=db7 */

sbit      db0 = db^0;            //sbit只能定义在函数体外,不能定义在函数体内
sbit      db1 = db^1;
sbit      db2 = db^2;
sbit      db3 = db^3;
sbit      db4 = db^4;
sbit      db5 = db^5;
sbit      db6 = db^6;
sbit      db7 = db^7;


/*      定义      rs      rw      e      */

sbit      rs = p1^3;
sbit      rw = p1^4;
sbit      e   = p1^5;

/*      具体电路变动时,只需在此处重新定义lcd的引脚与单片机的io引脚对应关系。      */
/*      ****************************************************************************      */


/*      该函数检查lcd是否空闲,空闲时返回0,忙时返回1      */

bit lcd_1602_check_bf()

{
/*      bf:      lcd忙标志位,如果bf=1,表明lcd内部忙,此时不能接受任何数据和指令。      */
bit bf;
/*      当rs=0、r/w=1、e=1时,bf输出到db7。每次访问lcd前,必须进行
该状态字的检查,只有在确认bf=0之后,才能进行lcd的读写操作。      */
rs = 0;
rw = 1;
e = 1;

bf = db7;
/*      函数返回bf      */
return bf;
}
离线Iraqi
发帖
393
只看该作者 3楼 发表于: 2008-01-26
/*      该函数显示字符串      */

extern void lcd_1602_write_character(unsigned char character);
extern void lcd_1602_write_command(unsigned char command);

void lcd_1602_display_string(unsigned char position,unsigned char *string)
/*      position指定显示的位置,string为要显示的字符串      */
{
lcd_1602_write_command(position | 0x80);      //指定显示位置
while(*string!='\0')
     {
     lcd_1602_write_character(*string);
     string++;
     }

}
离线Iraqi
发帖
393
只看该作者 4楼 发表于: 2008-01-26
#include <regx51.h>

/*      ****************************************************************************      */
/*      定义lcd的引脚与单片机的io引脚对应,程序中不在体现io引脚,这样程序可移植性较强      */

//* 定义 db=p2      */

sfr            db      = 0xa0;      

/* 定义      p2_0=db0      p2_1=db1      p2_2=db2      p2_3=db3      
           p2_4=db4      p2_5=db5      p2_6=db6      p2_7=db7 */

sbit      db0 = db^0;            //sbit只能定义在函数体外,不能定义在函数体内
sbit      db1 = db^1;
sbit      db2 = db^2;
sbit      db3 = db^3;
sbit      db4 = db^4;
sbit      db5 = db^5;
sbit      db6 = db^6;
sbit      db7 = db^7;

/*      定义      rs      rw      e      */

sbit      rs = p1^3;
sbit      rw = p1^4;
sbit      e   = p1^5;

/*      具体电路变动时,只需在此处重新定义lcd的引脚与单片机的io引脚对应关系。      */
/*      ****************************************************************************      */
extern bit lcd_1602_check_bf();      

/*      必须有该延时,否则该函数不能正常工作。      */
extern void time_delay(unsigned char time_delay);
/*      该函数写入字符显示数据到lcd      */
/*      character定义了写入的字符,调用该函数时参数为字符型,
如lcd_1602_write_character(Ə')      ,lcd即显示出该字符。*/
void lcd_1602_write_character(unsigned char character)
{
while(lcd_1602_check_bf());            //等待lcd空闲
/*      当rs=1,rw=0,e为下降沿时,数据写入lcd的数据寄存器      */
rs = 1;
rw = 0;
e = 1;      
/*      等待一个延时,否则不能正常工作      */
time_delay(1);
/*      e产生下降沿      ,写数据寄存器      */
db = character;
e = 0;      
}
离线Iraqi
发帖
393
只看该作者 5楼 发表于: 2008-01-26
/*      该函数写指令寄存器      */
#include <regx51.h>
/*      ****************************************************************************      */
/*      定义lcd的引脚与单片机的io引脚对应,程序中不在体现io引脚,这样程序可移植性较强      */

//* 定义 db=p2      */
sfr            db      = 0xa0;      

/* 定义      p2_0=db0      p2_1=db1      p2_2=db2      p2_3=db3      
           p2_4=db4      p2_5=db5      p2_6=db6      p2_7=db7 */

sbit      db0 = db^0;            //sbit只能定义在函数体外,不能定义在函数体内
sbit      db1 = db^1;
sbit      db2 = db^2;
sbit      db3 = db^3;
sbit      db4 = db^4;
sbit      db5 = db^5;
sbit      db6 = db^6;
sbit      db7 = db^7;
/*      定义      rs      rw      e      */
sbit      rs = p1^3;
sbit      rw = p1^4;
sbit      e   = p1^5;

/*      具体电路变动时,只需在此处重新定义lcd的引脚与单片机的io引脚对应关系。      */
/*      ****************************************************************************      */

extern bit lcd_1602_check_bf();      

/*      必须有该延时,否则该函数不能正常工作。      */
extern void time_delay(unsigned char time_delay);

/*      函数的变量"command"定义了指令字      */
void lcd_1602_write_command(unsigned char command)
{    
while(lcd_1602_check_bf());            //等待lcd空闲
/*      当rs=0,rw=0,e为下降沿时,指令写入lcd的指令寄存器      */
rs = 0;
rw = 0;
e = 1;      
/*      等待一个延时,否则不能正常工作      */
time_delay(1);
/*      e产生下降沿      ,写指令寄存器*/
db =command;
e = 0;

}
离线Iraqi
发帖
393
只看该作者 6楼 发表于: 2008-01-26
/*本函数作为不精确的延时使用*/

void time_delay(unsigned char time_delay)      //time_delay定义为时延长短
{

unsigned char time_delay_counter;            //延时设计中,作为循环时计数器

for (time_delay_counter=0; time_delay_counter<time_delay; time_delay_counter++)
{}

}
离线ba6iv
发帖
1285
只看该作者 7楼 发表于: 2008-01-28
不错!顶一下!!!!
离线LINHUOW
发帖
105
只看该作者 8楼 发表于: 2008-01-29
不错
离线kmnewton
发帖
226
只看该作者 9楼 发表于: 2010-02-10
写个简单的自动键程序!先记着。
离线XLDZZ
发帖
443
只看该作者 10楼 发表于: 2010-02-10
离线BD4EP
发帖
4228
只看该作者 11楼 发表于: 2010-02-11
唉,曾几何时,我也写单片机程序……当时只能用汇编,现在都能用c了,真幸福……
发帖
689
只看该作者 12楼 发表于: 2010-02-11
程序好长啊
一个简单的功能用得着吗?
ting13加上不超过20行的程序都做得到啦
简洁就是美啊
离线BG4IGX
发帖
7445
只看该作者 13楼 发表于: 2010-02-11
我有现成的。
离线BG4FQD
发帖
3406
只看该作者 14楼 发表于: 2011-05-28
楼主是个学院派,代码写的工整、而且比较易读,考虑的东西很多,所以略微有些拖沓。
我是个单片机的beginner,受益匪浅。
离线BG9CNF
发帖
987
只看该作者 15楼 发表于: 2011-06-09
有点划记忆功能。这一点就值得我相当膜拜学习了。
离线BG4FQD
发帖
3406
只看该作者 16楼 发表于: 2011-07-05
'
有点划记忆功能。这一点就值得我相当膜拜学习了。
'

大师,你咋又混到这儿了?
离线BG9CNF
发帖
987
只看该作者 17楼 发表于: 2011-07-06
到处找赵老师膜拜学习,能者为师,不分大小老少,职业。
离线BH3NEK
发帖
1497
只看该作者 18楼 发表于: 2011-07-06
好资料,学习了。
等电路图
离线bg5cvc
发帖
1106
只看该作者 19楼 发表于: 2011-07-09
拜读了
谢谢楼主