/*---------------------------------------------------------------- 零耗时低频宽脉冲软PWM信号控制Keil C51演示程序 C51文件PwmDemo.c HotPower@126.com 作于2004.11.17与大雁塔村队部 在uV3中对PWM信号进行"实时仿真"效果逼真。 -----------------------------------------------------------------*/ #include //#include #include
/*------------------------------------------------ AT89S5X SFR定义(REGX52.h中未定义) --------------------------------------------------*/ sfr AUXR = 0x8e; sfr WDTRST = 0xa6; sfr16 TIMEER2 = 0xcc; sfr16 RCAP2 = 0xca;
/*----------------------------------------------- PWM管脚定义 ------------------------------------------------*/ sbit PWM = P1^0;//可以为任意IO管脚
typedef struct Systemstruct{//系统数据结构 unsigned int PwmCount;//700~2300uS unsigned int RamTest;//内部ram自检变量 /*-------------------------------------------------------------------- 注意将STARTUP.A51中的IDATALEN改写为0,RamTest才能完成MCU掉电自检。 IDATALEN EQU 00H ; the length of IDATA memory in bytes. ---------------------------------------------------------------------*/ }SystemData;//系统数据结构(此时只是定义了一个新的数据类型SystemData)
//全局变量定义(全局结构) SystemData SystemBuffers;//申请系统数据结构缓冲区
#define T2_20mS -20000 //MCU主频12MHz,12分频,T2_20mS=20MS
/*---------------------------------------------------------------------- 系统函数 -----------------------------------------------------------------------*/ void MainInit(void);//系统初始化 void ClrWdt(void);//喂狗 void SystemInit(void);//系统初始化 void SystemSetup(void);//系统设置 void SystemIoInit(void);//系统接口初始化 void UserSetup(void);//用户运行环境设置 void TimeInit(void);//定时器定时参数初始化
/*----------------------------------------- 主程序初始化 -------------------------------------------*/ void MainInit(void)//系统初始化 { SystemIoInit();//系统接口初始化 ClrWdt();//清除看门狗计数器 if (SystemBuffers.RamTest != 0x55aa) {//内存测试 SystemInit();//系统上电初始化 } SystemSetup();//系统运行环境设置 UserSetup();//用户运行环境设置 }
void SystemInit(void)//系统初始化 { SystemBuffers.RamTest = 0x55aa;//内存初始化 }
void SystemSetup(void)//系统设置 { AUXR = 0x01;//关闭EMI TimeInit();//定时器定时参数初始化 IP = 0x20;//中断优先级ET2 }
void UserSetup(void)//用户运行环境设置 { /*-------------------------------------------- 在此加入用户运行环境设置代码 ----------------------------------------------*/ }
void SystemIoInit(void) { IE = 0x00;//关闭中断 P0 = 0xff;//P0口初始化 P1 = 0xfe;//P1口初始化,PWM=0 P2 = 0xff;//P2口初始化 P3 = 0xff;//P3口初始化 }
void TimeInit() { /*---------------------------------- 定时器0定时参数设置 ----------------------------------*/ TL0 = 0; TH0 = 0; // TR0 = 1;//启动定时器0 /*---------------------------------- 定时器1定时参数设置 ----------------------------------*/ TL1 = 0xfd; TH1 = 0xfd; PCON = 0x00;//SMOD_=0,GF0_=0;//清除疯狗标志 // TR1 = 1;//启动定时器1 /*---------------------------------- 定时器2定时参数设置 ----------------------------------*/ TIMEER2 = T2_20mS;//上电20mS后PWM开始工作 PWM = 0;//上电后无PWM信号 SystemBuffers.PwmCount = 700;//首次PWM脉宽为700uS RCAP2 = 0 - SystemBuffers.PwmCount;//首次PWM脉宽为700uS TR2 = 1;//启动定时器2(上电后20mS内PWM信号为低电平) /*---------------------------------- 定时器参数设置 ----------------------------------*/ TMOD = 0x22;//定时方式(8位自动装载) }
/*--------------------------------------------------------------------- 外部INT0中断服务程序(PWM+10uS) ----------------------------------------------------------------------*/ void int0proc() interrupt IE0_VECTOR using 2 { /*--------------------------------------------------------------------- 用户只能改写全局变量SystemBuffers.PwmCount,不能改写静态变量PwmCount ----------------------------------------------------------------------*/ if (SystemBuffers.PwmCount <= 2290) //PWM高电平脉宽上界-10 SystemBuffers.PwmCount += 10;//递增未越界 else SystemBuffers.PwmCount = 700;//递增越界翻到下界 }
/*--------------------------------------------------------------------- 定时器T0中断服务程序 ----------------------------------------------------------------------*/ void t0proc() interrupt TF0_VECTOR using 2 { if (PCON & GF0_) {//中断是从主循环内跳入的才能喂狗 ClrWdt();//清除看门狗计数器 PCON &= ~GF0_;//清除疯狗标志 } }
/*--------------------------------------------------------------------- 外部INT1中断服务程序(PWM-10uS) ----------------------------------------------------------------------*/ void int1proc() interrupt IE1_VECTOR using 2 { /*--------------------------------------------------------------------- 用户只能改写全局变量SystemBuffers.PwmCount,不能改写静态变量PwmCount ----------------------------------------------------------------------*/ if (SystemBuffers.PwmCount > 700) //PWM高电平脉宽下界 SystemBuffers.PwmCount -= 10;//递减未越界 else SystemBuffers.PwmCount = 2300;//递减越界翻到上界 }
/*------------------------------------ 定时器T1中断服务程序 ------------------------------------*/
void t1proc() interrupt TF1_VECTOR using 2 { /*-------------------------------------------- 在此加入用户代码(与串口复用T1) ----------------------------------------------*/ }
/*------------------------------------ 串口SIO中断服务程序 ------------------------------------*/
void sioproc() interrupt SIO_VECTOR using 2 { if (RI) {//接收中断 RI = 0; /*-------------------------------------------- 在此加入用户串口接收代码 ----------------------------------------------*/ } if (TI) {//发送中断 TI = 0; /*-------------------------------------------- 在此加入用户串口发送代码 ----------------------------------------------*/ } }
/*----------------------------------------------------------------------------- 定时器T2中断服务程序(20mS) 零耗时低频宽脉冲软PWM信号控制演示程序
软件工作环境及要求: MCU主频12MHz,软PWM控制IO模拟。PWM脉宽调节10uS PWM频率20mS=50Hz, PWM高电平脉宽700uS~2300uS,PWM低电平脉宽19300uS~17700uS
"零耗时"并非不耗时。只是没用软件空等待等恼人的函数。 其主要原理是利用低频宽脉冲软PWM信号的“低速”而T2的16位定时器自动装载功能。 T2在每个PWM周期内中断两次。即PWM高电平和PWM低电平各中断1次。 合理应用RCAP2的预装载功能并进行简单的减法运算而轻松完成任务的要求。
本演示程序只需经过简单的修改,即可实现变PWM频率等功能。 为演示方便未用宏定义,否则会更通用。但必须在“低频宽脉冲”的相对条件下。
本文纯属虚构,若有雷同请原谅! ------------------------------------------------------------------------------*/
void t2proc() interrupt TF2_VECTOR using 1 { static unsigned int PwmCount;//系统内部PWM高电平PwmCount(用户无法访问) /*----------------------------------------------------------------------------- PWM软件IO模拟,任务中未加关PWM控制,可以再加限定/PWM电平信号翻转标志。 即:SystemBuffers.PwmCount=0为关闭PWM电平信号输出(PWM=0) 注意SystemBuffers.PwmCount不能过小. 本软PWM控制模块与Windows的原则相同 --不主张用户直接开展PWM管脚,而是控制SystemBuffers.PwmCount变量。 例: ------------------------------------------------------------------------------- if (SystemBuffers.PwmCount == 0) {//关断PWM信号。(不主张用户直接开展PWM管脚) PWM = 0;//关闭PWM电平信号输出,并强迫执行RCAP2 = 0 - PwmCount;RCAP2=0(最宽) PwmCount = 0;//PWM高电平脉宽为0,PWM低电平脉宽为T2的最大定时时间。 } else ------------------------------------------------------------------------------*/ PWM = ~PWM;//PWM电平信号翻转
TF2 = 0;//清除标志 if (PWM) {//在PWM高电平时至少有700uS的预算时间 /*--------------------------------------------------------------------- 用户只能改写全局变量SystemBuffers.PwmCount,不能改写静态变量PwmCount ----------------------------------------------------------------------*/ PwmCount = SystemBuffers.PwmCount;//只在PWM上升沿处取用户PWM高电平PwmCount /*------------------------------------------------------------------------------ 此时RCAP2早已将PWM高电平PwmCount装入到TIMEER2中 故此时应该计算PWM低电平20mS-PwmCount到RCAP2中 ------------------------------------------------------------------------------*/ // RCAP2 = 0 - (20000 - PwmCount);//注意定时器是+1器 RCAP2 = PwmCount - 20000;//(优化计算)注意定时器是+1器(RCAP2首次为-19300) } else {//在PWM低电平时至少有17700uS的预算时间 /*------------------------------------------------------------------------------ 此时RCAP2早已将PWM低电平20mS-PwmCount装入到TIMEER2中 故此时应该计算PWM高电平PwmCount到RCAP2中 -------------------------------------------------------------------------------*/ RCAP2 = 0 - PwmCount;//注意定时器是+1器(RCAP2首次为-700) } /*------------------------------------------------------------------------------ PWM高电平RCAP2定时时间 + PWM低电平RCAP2定时时间 = PWM周期20mS -------------------------------------------------------------------------------*/ }
void ClrWdt(void)//喂狗 { WDTRST = 0x1e;//89s52内狗 WDTRST = 0xe1;//89s52内狗 }
void main(void) { MainInit();//系统初始化 while (1) {//主循环 IE |= 0xbf;//保证全部中断可靠 TCON |= 0x55;//保证定时器打开,外部中断为边沿触发. PCON |= GF0_ | IDL_;//喂疯狗(GF0_=1)并进入空闲状态(IDL_=1) _nop_(); _nop_(); } }
|
文章评论(0条评论)
登录后参与讨论