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

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

上一主题 下一主题
离线Iraqi
发帖
393
只看该作者 20楼 发表于: 2011-07-11
时间太长了,记不得当时怎么写的代码了,也不知道点划记忆的算法对不对了。当时试的时候好像还可以,不知道有没有bug!感谢顶帖,呵呵。
离线BG4FQD
发帖
3406
只看该作者 21楼 发表于: 2011-07-11
'
时间太长了,记不得当时怎么写的代码了,也不知道点划记忆的算法对不对了。当时试的时候好像还可以,不知道有没有bug!感谢顶帖,呵呵。
'

按键的处理我个人觉得比较有创意,采用了循环队列,有点像 dos的键盘处理方式。

代码中捏发支持的有点问题,捏发时候点划不能交替出现,这是 bg9cnf发现的,

我觉得应作如下更改

把 dot 按键处理中的:
  dot_duration=2*dot_time;      //时间间隔可根据手感调整

改为:
if (paddle_dash_register==0) // 如果划按下,dot的循环周期也应该和dash一致,才能出现点划交替出现
  dot_duration=4*dot_time;
else
  dot_duration=2*dot_time;
离线Iraqi
发帖
393
只看该作者 22楼 发表于: 2011-07-12
'
按键的处理我个人觉得比较有创意,采用了循环队列,有点像 dos的键盘处理方式。
代码中捏发支持的有点问题,捏发时候点划不能交替出现,这是 bg9cnf发现的,
我觉得应作如下更改
把 dot 按键处理中的:
  dot_duration=2*dot_time;      //时间间隔可根据手感调整
改为:
if (paddle_dash_register==0) // 如果划按下,dot的循环周期也应该和dash一致,才能出现点划交替出现
  dot_duration=4*dot_time;
else
  dot_duration=2*dot_time;
'

呵呵你们都试过这个代码了!还能检查出bug,甚感欣慰,找到同好了!
离线Iraqi
发帖
393
只看该作者 23楼 发表于: 2011-07-12
找到了当时的最终版主程序:支持点划连发、点划记忆、点划插入、点划交替
#include <regx51.h>
#define queue_size 6      //定义自动键的缓存队列长度。
#define cw_tone_frequency      800      //定义侧音频率。可定义成变量,在程序中进行设置,本程序忽略。
#define dot 0      //定义常数表示点
#define dash 1      //定义常数表示划
/////////////////////////////////////////////////////////////////////////////////////////////
//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 char dot_time=7;      //本程序按每分钟12个word(paris)固定设置:1个点的时间约为100ms.
unsigned char speed=20;            //定义显示的发码速度
////////////////////////////////////////////////////////////////////////////////////////////
// 定义电键的输入端,增加程序的可读性和电路的可移植性
sbit paddle_dot=p3^6;
sbit paddle_dash=p3^7;

sbit dot_time_key=p3^3;      //定义调整发码速度键
     
// 定义电键的输出端,增加程序的可读性和电路的可移植性
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++;

// 每次中断发生时读取paddle_dot和paddle_dash的状态,与上一次paddle_dot和paddle_dash的状态进行比较      
// 根据比较结果,决定点(0)划(1)如何进入缓存队列      

if(paddle_dot==0)//如果paddle_dot被按下
     {
     
     if(paddle_dash==1)//如果paddle_dot被单独按下,paddle_dash未被按下
           {      
           //      如果上一次按键状态paddle_dot_register为0,即常按paddle_dot,以一定的时间间隔连续发点      
           if (paddle_dot_register==0)      
                 {
                 if(dot_duration--==0)      paddle_dot_register=1;
                 }
           
           //      如果前次按键状态paddle_dot_register为1,即paddle_dot被按后放开,则发点      
           if      (paddle_dot_register==1)      
                 {
                 //      本程序假定队列永远不满,不做队列是否满的条件判断      
                 //      点入队列,队尾下标要加1。      
                 dot_dash_buffer_tail= (dot_dash_buffer_tail+1)%queue_size;
                 dot_dash_buffer[dot_dash_buffer_tail]=dot;
                       
                 paddle_dot_register=paddle_dot;      //记录本次paddle_dot按键状态
                 dot_duration=2*dot_time-dot_time/4;      //设定连续发点的时间间隔
                 }
            }

     if(paddle_dash==0)//如果paddle_dash也被按下
           {
           //      如果paddle_dot_register==0,即paddle_dot前一次已被按下,
           //      此时如果paddle_dash刚被按下,即paddle_dash_register==1,则插入划
           if(paddle_dot_register==0&&paddle_dash_register==1)
                 {
                 //      本程序假定队列永远不满,不做队列是否满的条件判断      
                 //      划入队列,队尾下标要加1。      
                 dot_dash_buffer_tail= (dot_dash_buffer_tail+1)%queue_size;
                 dot_dash_buffer[dot_dash_buffer_tail]=dash;
                       
                 paddle_dash_register=paddle_dash;      //记录本次paddle_dash按键状态
                 dot_duration=4*dot_time-dot_time/2;      //设定点划交替状态下点和划的到达时间
                 dash_duration=dot_duration+2*dot_time;      
                 }

           //      如果paddle_dot_register==0&&paddle_dash_register==0,则进入点划交替状态,等待点到达      
            if(paddle_dot_register==0&&paddle_dash_register==0)
                 {
                 if(dot_duration--==0)      paddle_dot_register=1;
                 }
            }
     }
else paddle_dot_register=paddle_dot;      //paddle_dot未被按下,只记录本次paddle_dash按键状态
     

if(paddle_dash==0)//如果paddle_dash被按下
     {
     if(paddle_dot==1)//如果paddle_dash被单独按下,paddle_dash未被按下
           {
           //      如果上一次按键状态paddle_dash_register为0,即常按paddle_dash,以一定的时间间隔连续发划      
           if (paddle_dash_register==0)
                 {      
                 if(dash_duration--==0)      paddle_dash_register=1;
                 }
     
           //      如果前次按键状态paddle_dash_register为1,即paddle_dash被按后放开,则发划      
           if(paddle_dash_register==1)
                 {
                 //      本程序假定队列永远不满,不做队列是否满的条件判断      
                 //      划入队列,队尾下标要加1。      
                 dot_dash_buffer_tail= (dot_dash_buffer_tail+1)%queue_size;
                 dot_dash_buffer[dot_dash_buffer_tail]=dash;
                       
                 paddle_dash_register=paddle_dash;      //记录本次paddle_dash按键状态
                 dash_duration=3*dot_time+dot_time/3;      //设定连续发划的时间间隔
                 }
           }
     if(paddle_dot==0)//如果paddle_dot也被按下      
           {
           //      如果paddle_dash_register==0,即paddle_dash前一次已被按下,
           //      此时如果paddle_dot刚被按下,即paddle_dot_register==1,则插入点      
           if(paddle_dash_register==0&&paddle_dot_register==1)
                 {
                 //      本程序假定队列永远不满,不做队列是否满的条件判断      
                 //      点入队列,队尾下标要加1。      
                 dot_dash_buffer_tail= (dot_dash_buffer_tail+1)%queue_size;
                 dot_dash_buffer[dot_dash_buffer_tail]=dot;
                       
                 paddle_dot_register=paddle_dot;      //记下本次paddle_dot的按键状态
                 dash_duration=2*dot_time-dot_time/2;      //设定点划交替状态下点和划的到达时间
                 dot_duration=dash_duration+4*dot_time;
                 }

           //      如果paddle_dot_register==0&&paddle_dash_register==0,则进入点划交替状态,等待划到达      
            if(paddle_dot_register==0&&paddle_dash_register==0)
                 {
                 if(dash_duration--==0)      paddle_dash_register=1;
                 }
           }
     }
else paddle_dash_register=paddle_dash;            //paddle_dash未被按下,只记录本次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 void lcd_1602_write_command(unsigned char command);
extern void lcd_1602_write_character(unsigned char character);
extern void lcd_1602_display_string(unsigned char position,unsigned char *string);
extern void lcd_1602_display_wpm(unsigned char position,unsigned char i);
//////////////////////////////////////////////////////////////////////////////////

extern unsigned char getkey(void);

main(void)
{

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

dot_time_key=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_wpm(0x00|0x80,speed);

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 dot:
                       {
                       send_dot();                  
                       lcd_1602_write_character('.');
                       break;
                       }
                 case dash:      
                       {
                       send_dash();                              
                       lcd_1602_write_character('_');
                       break;
                       }
                  }
           
           //      缓冲区队首指针后移,已发完的点或划出队列      
           dot_dash_buffer_head = (dot_dash_buffer_head+1)%queue_size;
           
           //      对发完后的时间间隔开始计时      
           clear_lcd=0;
           }
/////////////////////////////////////////////////////////////////////////////////////////////      
     //以下程序扫描键盘,调整发码速度和侧音频率
     else
           {
           switch (getkey())
                 {
                 case 0:      //键盘返回0调整发码速度,调整方式为循环方式
                       {
                       if (speed==12)
                             {
                             speed=15;
                             dot_time=8;
                             lcd_1602_display_wpm(0x00|0x80,speed);
                             break;
                             }
                       if (speed==15)
                             {
                             speed=20;
                             dot_time=7;
                             lcd_1602_display_wpm(0x00|0x80,speed);
                             break;
                             }
                       if (speed==20)
                             {
                             speed=12;
                             dot_time=10;
                             lcd_1602_display_wpm(0x00|0x80,speed);
                             break;
                             }
                        }
     
                  case 3:{}
                 }
            }
     }
//////////////////////////////////////////////////////////////////////////////////////////////
}
离线Iraqi
发帖
393
只看该作者 24楼 发表于: 2011-07-12
找到了以前完整的的代码!
离线Iraqi
发帖
393
只看该作者 25楼 发表于: 2011-07-12
把上面的程序移植到pic12f629上的全部代码,去掉了显示部分,编译后可运行!
附件: pic12f629_Paddle.txt (0 K) 下载次数:233
离线BG4FQD
发帖
3406
只看该作者 26楼 发表于: 2011-07-18
点划插入 是什么意思?

按键识别怎么算法这么复杂呢?
离线fjwayne
发帖
741
只看该作者 27楼 发表于: 2011-09-29
好资料,学习了。
等电路图
离线BH4TXN
发帖
15095
只看该作者 28楼 发表于: 2012-02-08
嗯~嗯~抄下来学习下~
离线BH4TXN
发帖
15095
只看该作者 29楼 发表于: 2012-03-11
再学一次~
离线BG3TCU
发帖
746
只看该作者 30楼 发表于: 2012-10-26
留个爪爪 嘻嘻
离线BG3THP
发帖
12
只看该作者 31楼 发表于: 2013-02-12
好程序,收藏一下
离线bd3tt
发帖
1660
只看该作者 32楼 发表于: 2014-04-03
下载了,谢谢。
========================================
ba3tt  (ex:bd3tt,bg3tt,bg3-4-005)
ba3tt的小菜园:http://www.qsl.net/bg3tt
离线bh1rar
发帖
83
只看该作者 33楼 发表于: 2014-04-23
学习了
离线bg4joa
发帖
29
只看该作者 34楼 发表于: 2014-05-27
记号,学习了。。。。。
机器都是二手的,天线都是自制的,没搞过原装的。。。。
离线bg7doz
发帖
492
只看该作者 35楼 发表于: 2014-05-27
抄收,有时间试试,73。
离线aqqw
发帖
1245
只看该作者 36楼 发表于: 2014-06-05
这个不错,下载学习一下
--------------------
喜欢无线电
喜欢DIY!!
地址:桂林市临桂西城工业区福达曲轴公司
邮编:541100
BG7RMU[/COLOR][/SIZE]
离线bg6ib
发帖
72
只看该作者 37楼 发表于: 2014-06-22
收藏了,感谢楼主
离线bd4igh
发帖
4250
只看该作者 38楼 发表于: 2014-10-03
能写出来就很利害!
王安林
山东.日照
曾用呼号BG6AG
安徽境内首个业余台
QQ:317311229
手机:13376330683
Email  :wal 696@163.com.
离线BG3LL
发帖
650
只看该作者 39楼 发表于: 2014-10-03
认真学习 一下
对楼主实在是佩服!
呼号:BG3LL   会员证号:12839
地址:内蒙古赤峰市克旗经棚镇解放路199号
面包会有的 牛奶会有的 IC703 也会有的