本帖最后由 LiMeng 于 2018-4-4 09:30 编辑
我做出来了,方案如下:用了STC公司最新的STC8单片机,STC8单片机共有5个定时器,分别产生前五个方波,100Hz的定时器进中断进行分频产生最后一个方波,并为按键检测提供状脉冲。
单片机的定时器统一采用自动重载模式,并在溢出后直接翻转I/O口,整个过程除了最后10Hz进中断,其他均为硬件产生,故精度是以单片机的晶振精度为基准的。程序如下:
/***********************************************************************
* 文 件 名: 方波发生器
* 使用芯片: STC8A8K64S4A12
* 使用晶振: 24.0000MHz
* 硬件连接: P0.0连接按键
* 描述功能: P5.4输出3MHz,P3.5输出1MHz,P3.4输出100KHz,P1.3输出10KHz,P0.5输出1KHz,P0.7输出100Hz,P04输出10Hz,P0.1、P0.2为单脉冲
* 日 期: 2018/03/20
* 作 者: 李猛
* 版 本: V1.0
* 修改记录: 无
******************头文件***********************************************/
#include <STC8.H>
#include <intrins.h>
/*****************宏定义***********************************************/
#define CLKO 24000000 //系统时钟频率
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
//=========定时器计算公式==================
#define Time_1T_ms CLKO/1000 //定时器1T模式下毫秒级延时计算公式
#define Time_12T_ms CLKO/12/1000 //定时器12T模式下毫秒级延时计算公式
#define Time_1T_us CLKO/1000000 //定时器1T模式下微秒级延时计算公式
#define Time_12T_us CLKO/12/1000000 //定时器12T模式下微秒级延时计算公式
/*****************定义全局变量******************************************/
bit KEY_ON ,FangBo; //定义标志位
/*************************************************************************
* 函 数 名: Cksel_Init
* 功 能: 初始化系统时钟
* 入口参数: 无
* 出口参数: 无
* 备 注: 无
*************************************************************************/
void Cksel_Init(void)
{
P_SW2 = 0x80; //特殊功能寄存器位于扩展RAM区域,访问需先将P_SW2的BIT7设置为1
IRC24MCR = 0x80; //使用内部24MHz晶振
while(!(IRC24MCR & 1)); //等待时钟稳定
CLKDIV = 0x00; //主时钟不分频
CKSEL = 0x70; //选择外部输入时钟信号并在P5.4输出系统时钟的八分频
P_SW2 = 0X00;
}
/*********************************************************************
* 函 数 名: IO_Init初始化函数
* 功 能: 初始化I/O口
* 入口参数: 无
* 出口参数: 无
* 备 注:
* PxM1 PxM0
* 0 0 准双向I/O
* 0 1 推挽输出
* 1 0 高阻输入
* 1 1 开漏输出
***********************************************************************/
void IO_Init(void)
{
P0M1 = 0x00; P0M0 = 0x00;// P0 = 0x00; //P0口设置成准双向I/O 同时全部置低
P1M1 = 0x00; P1M0 = 0x00;// P1 = 0x00; //P1口设置成准双向I/O 同时全部置低
P2M1 = 0x00; P2M0 = 0x00;// P2 = 0x00; //P2口设置成准双向I/O 同时全部置低
P3M1 = 0x00; P3M0 = 0x00;// P3 = 0x00; //P3口设置成准双向I/O 同时全部置低
P4M1 = 0x00; P4M0 = 0x00;// P4 = 0x00; //P4口设置成准双向I/O 同时全部置低
P5M1 = 0x00; P5M0 = 0x00;// P5 = 0x00; //P5口设置成准双向I/O 同时全部置低
P6M1 = 0x00; P6M0 = 0x00;// P6 = 0x00; //P6口设置成准双向I/O 同时全部置低
P7M1 = 0x00; P7M0 = 0x00;// P7 = 0x00; //P7口设置成准双向I/O 同时全部置低
}
/*********************************************************************
* 函 数 名: Routine_Init
* 功 能: 初始化中断
* 入口参数: 无
* 出口参数: 无
* 备 注: 在主函数初始化的最后开启总中断(EA = 1;)
* IP、IP2 IPH、IP2H 中断优先级控制寄存器
* 0 0 最低级(0级)
* 0 1 较低级(1级)
* 1 0 较高级(2级)
* 1 1 最高级(3级)
***********************************************************************/
void Routine_Init(void)
{
//===============T0============================1MHz 0.5us P3.5
TL0 = 65536-5*Time_1T_us/10; //对定时器0赋初值 1T
TH0 = 65536-5*Time_1T_us/10 >> 8;
TMOD &= 0; //0000 0000
AUXR |= T0x12; //1000 0000
INTCLKO |= T0CLKO; //0000 0001 溢出自动取反
TF0 = 0; //T0溢出标志位清零
TR0 = 1; //T0运行控制位
// ET0 = 1; //定时/计数器T0中断允许位
//===============T1============================100KHz 5us P3.4
TL1 = 65536-5*Time_1T_us; //对定时器1赋初值 1T
TH1 = 65536-5*Time_1T_us >> 8;
TMOD &= 0; //0000 1000
AUXR |= T1x12; //0100 0000
INTCLKO |= T1CLKO; //0000 0010 溢出自动取反
TF1 = 0; //T1溢出标志位清零
TR1 = 1; //T1运行控制位
// ET1 = 1; //定时/计数器T1中断允许位
//===============T2============================10KHz 50us P1.3
TL2 = 65536-50*Time_1T_us; //对定时器2赋初值 1T
TH2 = 65536-50*Time_1T_us >> 8;
AUXR |= 0x14; //0001 0100
INTCLKO |= T2CLKO; //0000 0010 溢出自动取反
// IE2 |= ET2; //定时/计数器T2中断允许位
//===============T3============================1KHz 500us P0.5
TL3 = 65536-50*Time_1T_us*10; //对定时器3赋初值 1T
TH3 = 65536-50*Time_1T_us*10 >> 8;
T4T3M |= 0x0B; //0000 1011
// IE2 |= ET3; //定时/计数器T3中断允许位
//===============T4============================100Hz 5ms P0.7
TL4 = 65536-5*Time_12T_ms; //对定时器3赋初值 12T
TH4 = 65536-5*Time_12T_ms >> 8;
// T4T3M &= 0x0F; //0000 1111
T4T3M |= 0x90; //1001 0000
IE2 |= ET4; //定时/计数器T4中断允许位
}
/*************************************************************************
* 函 数 名: Read_Key
* 功 能: 监测按键子程序
* 入口参数: 无
* 出口参数: Key_return
* 备 注: 无
*************************************************************************/
#define Key_input P00 //按键输入端口
#define Key_state_0 0 //检测按键状态
#define Key_state_1 1 //确认按键状态
#define Key_state_2 2 //待释放按键状态
u8 Read_Key(void)
{
static u8 Key_state = 0; //静态局部变量,仅执行一次
static u8 Key_return = 0;
switch(Key_state)
{
case Key_state_0: //检测阶段
if(!Key_input) //如果有按键按下
Key_state = Key_state_1; //转入确认阶段
break;
case Key_state_1: //确认阶段
if(!Key_input) //若还有按键按下
{
Key_state = Key_state_2; //转入释放阶段
Key_return = 1; //返回值置“1”
}
else
{
Key_state = Key_state_0; //如果没有按键按下,则认为是抖动,返回检测阶段
Key_return = 0; //返回值置“1”
}
break;
case Key_state_2: //待释放阶段
if(!Key_input) //等待按键释放
Key_state = Key_state_2; //转入检测阶段
else
{
Key_return = 0;
Key_state = Key_state_0; //转入检测阶段
}
break;
}
return Key_return; //返回状态
}
/*************************************************************************
* 函 数 名: main主函数
* 功 能: 执行主程序
* 入口参数: 无
* 出口参数: 无
* 备 注: 无
*************************************************************************/
void main(void)
{
Cksel_Init(); //初始化系统时钟
IO_Init(); //I/O口初始化
Routine_Init(); //中断初始化函数
EA = 1; //总中断允许位
while(1) //死循环
{
if(KEY_ON) //10ms时间到
{
KEY_ON = 0; //清除标志位
switch(Read_Key())
{
case 0: //检测阶段
P01 = 1;
P02 = 0;
break;
case 1: //确认阶段
P01 = 0;
P02 = 1;
break;
}
}
};
}
/*************************************************************************
* 函 数 名: TM4_Rountine
* 功 能: 定时器4中断服务程序
* 入口参数: 无
* 出口参数: 无
* 备 注: 无
**************************************************************************/
void TM4_Rountine(void) interrupt 20
{
u8 j,i; //定义变量
AUXINTIF &= ~T4IF; //清中断标志位
if(++j >= 2) //两分频
{
j = 0;
KEY_ON = 1; //置按键标志位
if(++i >= 5) //五分频
{
i = 0;
P04 = !P04; //10Hz P1.0
}
}
}
|