1.Abstract
做这个是受朋友之邀,用在控制电机转动的方面。他刚好在一家好的单位实习,手头工作比较多,无暇分身,所以找我帮忙做个模型。要求很明晰,PWM的频率在0~1KHz范围内,占空比0~99%范围内,二者均可调。抄下指标以后,回到实验室,细细分析以后,决定用MCU来实现一下,毕竟只分析,无实际结果也不是一个好的交代。
2.Content
2.1 理论分析
归根结底来说,是一个时序逻辑,即PWM输出波形是随着时间的推移而变化。用时序图的方式解释更明晰些。
basic_time由内部产生,main_cnt记录的是要输出的PWM占空比,sub_cnt用来输出PWM波形。图中是以占空比为80%为例。从上往下,从左往右看,深色部分表示上一次的状态,当设置为占空比为80%时,在basic_time的上升沿下,子计数器开始从0到99计数,当计数个数满设定的占空比时,PWM引脚输出低电平,直至下一次重新计数开始,PWM引脚恢复高电平。
使用CPLD/FPGA或许更容易实现这个逻辑,使用微控制器就需要转一转思维,将这里的basic_time转换成计数器,在MCU的时钟驱动下逐步计数,计满预定的值以后再重新计数。它的功能正如它的名称,单位时钟产生器。
波形产生原理就如上所述了,还有一个要求就是能对PWM的频率和占空比进行控制,好在一般MCU有串行通信接口,可以避免使用外部资源,再适合不过了。将程序写得完整一点,加入数据正确辨识处理等功能。
2.2 程序编码
2.2.1基于传统MCS-51的MCU程序编码
/* -------------------------------------------------------------- File Name: PWM File Function: 频率、占空比均可调的程序 File Dependency: system library -- intrins.h File Note: 串口进行数据输入,P1.7脚PWM输出 频率范围 0 - 999, 占空比 0 - 99 晶振11.0592M ----------------------------------------------------------------*/ #include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义 #include <intrins.h> sbit PWM_OUT = P1^7; // PWM 引脚输出口 unsigned int t=0; // time count unsigned char rx[20]=0; // 接收字符存储 unsigned char n=0; // 字符存储 count unsigned char fre=0; // 频率 unsigned char duty=0; // 占空比 unsigned int n_fre=0; // 换算后,频率对应需计数的个数 unsigned int n_duty=0; // 换算后,占空比应需计数的个数 unsigned char rx_end_flag=0; unsigned char rx_full_flag=0; /*------------------------------------------------ 函数声明 ------------------------------------------------*/ void SendStr(unsigned char *s); void MCU_Answer(); void Data_Process(); void Send_LNK(); void LCD_Refresh(); /*------------------------------------------------ Name: Init_UART Function: 串口初始化 Input: None Output: None Note: 通信方式 8-1,baudrate:9600 ------------------------------------------------*/ void Init_UART (void) { SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收 TMOD |= 0x20; // TMOD: timer 1, mode 2, 8-bit 重装 TH1 = 0xFD; // TH1: 重装值 9600 波特率 晶振 11.0592MHz TL1 = 0xFD; TR1 = 1; // TR1: timer 1 打开 EA = 1; //打开总中断 TI = 0; RI = 0; ES = 1; // ES = 1; //打开串口中断 } /*------------------------------------------------- Name: Init_Timer0 Function: 定时器0初始化 Input: None Output: None Note: 11.0592M / 100/ 100 晶振频率/主计数百分化/从计数百分比 --------------------------------------------------*/ void Init_Timer0(void) { TMOD |= 0x02; // Timer 0, Mode 2, 8-bit reload TH0 = 0xA3; TL0 = 0xA3; ET0 = 1; TR0 = 1; } void Short_Delay() //短暂延时,消除串口工作频率太快反应不过来的问题 { unsigned char i=100,j=100; while(--i) --j; } void SendByte(unsigned char dat) // 发送一个字符 { SBUF = dat; } void SendStr(unsigned char *s) // 发送一个字符串 { while(*s != '