#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;
}
}
}