PWM调速的C语言程序编写
- 格式:doc
- 大小:30.00 KB
- 文档页数:2
PWM调速的C语言程序编写关于PWM的原理在上一篇文章中已经说的很详细了,现在就细说一下pwm C语言程序的编写。
C语言中PWM的编写有这么几种方法;一、用普通的I/O 口输出的PWM ,二、使用定时计数器编写,三、就是使用片内PWM了。
1 先说使用普通的I\O口编写PWM程序了。
使用I/O口输出PWM波形你必须首先明白PWM他的实质是:调制占空比,占空比就是波形中高电平的长度与整个波长的比值。
我们写C语言的目的是写PWM波形的一个周期。
在这个周期内高低电平的比值是可以改变的。
这也就符合了PWM的原意脉宽调制。
即高电平的宽度的调制。
当然了PWM他也可用于改变频率,我们这里只先说他改变脉宽。
一旦我们的C语言程序写完那么他产生的PWM波形的频率就一定了。
(也可写频率变化的PWM,难度有点大)一般我们控制使用1K到10K的PWM波进行控制。
当然了你也可在要求不是很高的地方使用频率更低的PWM波。
比如在飞思卡尔智能车比赛中我们学校使用的PWM波频率只有600HZ.我们要改变一个PWM波周期内的高电平的宽度显然需要将一个PWM波的周期分成单片机可以控制的N个小的周期,N的取值越大你的调速等级越高,但产生的PWM频率就越低。
我们下面以实现100级调速为例编写PWM程序。
先写出程序再慢慢给大家分析void pwm (uchar x,uint y) //X 为占空比 Y为函数使用时间{ uint i,j,a,b;for(i=y;i>0;i--)//定时外函数{for(j=7;j>0;j--)//定时内函数{for(a=y;a>0;a--) / /PWM波高电平宽度{PORTA=0X01;}for(b=100-y;b>0;b--) //PWM低电平宽度{PORTA=0X00;}}}}这个程序够简单吧轻松的实现AVR单片机的PA.0口输出7KHZ左右的PWM脉冲你可以将PORTA=0X01;改为P1.0=0X01;就可以移植到51单片机上了为什么使用参数Y定时是因为用普通I/O口控制它的开关没有使用定时器编写的灵活。
下面介绍一下单片机PWM控制C语言实例,单片机PWM可以应用在许多方面,如电机调速、温度控制、压力控制等。
PWM—脉冲宽度调制,是一种周期一定而高低电平可调的方波信号。
广泛使用电机调速的项目中,用了S52单片机的T2定时器产生PWM波信号,用于控制直流电机的转速,虽然电机的平均速度与占空比不是严格的线性关系,但是在调节占空比可以明显的看出电机转速发生了改变,也算是满足了课题的要求。
下面复习一下PWM的知识吧:PWM—脉冲宽度调制,当输出脉冲的频率一定时,输出脉冲的占空比越大,相对应的输出有效电压越大。
PWM可以应用在许多方面,如电机调速、温度控制、压力控制等。
T1为脉冲宽度(就是导通时间),周期为T,则输出电压的平均值为U=VCC*T1/T=a*VCC,a是占空比,变化范围为0≤a≤1。
VCC 为电源电压。
所以当电源电压不变的情况下,输出电压的平均值U取决于占空比a的大小,改变a的大小就可以改变输出电压的平均值,这就是PWM的工作原理。
采用T2定时器产生PWM脉冲极其精确,误差只在几个us。
// 单片机PWM控制C语言实例文件名: T2PWM.c// 单片机PWM控制C语言实例功能: 用T2定时器产生PWM波,频率实调1khz // 单片机PWM控制C语言实例说明: 单片机AT89S52,晶振12MHZ;#include "reg52.h"#define uint unsigned int#define uchar unsigned charsbit PWM = P1^1;uchar pluse; //占空比寄存器void Timer2() interrupt 5static uchar time;TF2=0;if(++time==pluse) PWM=0; //达到脉宽设定值时,输出PWM低电平 else if(time==40) //PWM的频率为1khz左右{time=0;PWM=1;}}void InitTimer2(void) //初始化函数{RCAP2H = 0xff ;//定时25us初值RCAP2L = 0x0e7;//ET2=1;EA=1;TR2=1;}void main(void){InitTimer2();while(1)pluse=20;}}把PWM波的周期定为1ms,占空比分40级可调(即每级差2.5%),这样定时器T2每25us产生一个定时中断,每40次中断后进入下一个PWM波的周期。
基于C51单片机的直流电机PWM调速控制--SQ这是最近一阶段自己学习所获,现分享与大家。
这里采用A T89C52单片机做主控制芯片,实现两路直流电机的PWM调速控制,另外还可以实现转向、显示运行时间、显示档位等注:考虑小直流电机自身因素,调速范围仅设有四级电路原理图:C语言程序源代码:/******************** 硬件资源分配*********************/数码管:显示电机状态(启停、正反、速度)、运行时间、是否转弯按键:K4 启动/暂停K3 正反转/转弯允许K2 加速/左转/运行时间清零K1 减速/右转/停止定时器:T0 数码管动态显示,输出PWMT1 运行时间记录********************************************************//*******主程序文件PWM.c******/#include <reg52.h>#include "Afx.h"#include "Config.c"#define CIRCLE 5 //脉冲周期//按键定义uchar key,key_tmp=0, _key_tmp=0;//显示定义uchar LedState=0xF0; //LED显示标志,0xF0不显示,Ox00显示uchar code LED_code_d[4]={0xe0,0xd0,0xb0,0x70}; //分别选通1、2、3、4位uchar dispbuf[4]={0,0,0,0}; //待显示数组uchar dispbitcnt=0; //选通、显示的位uchar mstcnt=0;uchar Centi_s=0,Sec=0,Min=0; //分、秒、1%秒//程序运行状态标志bit MotState=0; //电机启停标志bit DirState=0; //方向标志0前,1后uchar State1=-1;uchar State2=-1;uchar State3=0;uchar State4=-1;uchar LSpeed=0;uchar RSpeed=0;//其他uint RunTime=0;uint RTime_cnt=0;uint LWidth;uint RWidth; //脉宽uint Widcnt=1;uint Dispcnt;//函数声明void key_scan(void);void DisBuf(void);void K4(void);void K3(void);void K2(void);void K1(void);void disp( uchar H, uchar n );void main(void){P1|=0xF0;EA=1;ET0=1;ET1=1;TMOD=0x11;TH0=0xFC;TL0=0x66; //T0,1ms定时初值TH1=0xDB;TL1=0xFF; //T1,10ms定时初值TR0=1;Widcnt=1;while(1){key_scan();switch(key){case 0x80: K1(); break;case 0x40: K2(); break;case 0x20: K3(); break;case 0x10: K4(); break;default:break;}key=0;DisBuf();LWidth=LSpeed;RWidth=RSpeed;}}//按键扫描**模拟触发器防抖void key_scan(void){key_tmp=(~P3)&0xf0;if(key_tmp&&!_key_tmp) //有键按下{key=(~P3)&0xf0;}_key_tmp=key_tmp ;}//按键功能处理/逻辑控制void K4(void){if(State4==-1){State4=1;TR1=1;dispbuf[3]=1;LedState=0x00; //打开LEDMotState=1; //打开电机LSpeed=1;RSpeed=1; //初速设为1}else if(State4==1){State4=0;TR1=0;MotState=0; //关闭电机}else if(State4==0){MotState=1;if(State3==0){State4=1;TR1=1;}else if(State3==1){LSpeed=2;RSpeed=2;}}}void K3(void){if(State4==1)DirState=!DirState;if(State4==0){if(State3==0){State3=1; //可以转向标志1可以,0不可以TR1=1;dispbuf[3]=9;MotState=1;LSpeed=2;RSpeed=2;}else if(State3==1){State3=0;TR1=0;dispbuf[3]=0;MotState=0;}}}void K2(void){if(State4==1&&LSpeed<4&&RSpeed<4){LSpeed++;RSpeed++;}else if(State4==0){if(State3==0){//State4=-1;//LedState=0xF0;MotState=0;Sec=0;Min=0;}else if(State3==1&&LSpeed<4&&RSpeed<4){//TurnState=0;LSpeed=2;RSpeed++;}}}void K1(void){if(State4==1&&LSpeed>1&&RSpeed>1){LSpeed--;RSpeed--;}else if(State4==0){if(State3==0){State4=-1;LedState=0xF0;MotState=0;}else if(State3==1&&LSpeed<4&&RSpeed<4){//TurnState=1;LSpeed++;RSpeed=2;}}}//显示预处理void DisBuf(void){if(RTime_cnt==100){Sec++;RTime_cnt=0;}if(Sec==60){Min++;Sec=0;}if(State4==1){dispbuf[0]=Sec%10;dispbuf[1]=Sec/10;dispbuf[2]=Min;if(!DirState) //正转dispbuf[3]=LSpeed;if(DirState) //反转dispbuf[3]=LSpeed+4;}if(State4==0){if(State3==0){dispbuf[0]=Sec%10;dispbuf[1]=Sec/10;dispbuf[2]=Min;dispbuf[3]=0;}if(State3==1){dispbuf[0]=RSpeed;dispbuf[1]=LSpeed;dispbuf[2]=Min;dispbuf[3]=9;}}}//LED驱动void disp( uchar H, uchar n ){P1=n;P1|=LedState ;P1|=LED_code_d[H];}//T0中断**显示/方波输出void Time_0() interrupt 1{TH0=0xFC;TL0=0x66;Widcnt++;Dispcnt++;//电机驱动/方波输出if(Widcnt>CIRCLE){Widcnt=1;}if(Widcnt<=LWidth)LMot_P=!DirState&&MotState;elseLMot_P=DirState&&MotState;LMot_M=DirState&&MotState;if(Widcnt<=RWidth)RMot_P=!DirState&&MotState;elseRMot_P=DirState&&MotState;RMot_M=DirState&&MotState;//显示if(Dispcnt==5){disp(dispbitcnt,dispbuf[dispbitcnt]);dispbitcnt++;if(dispbitcnt==4){dispbitcnt=0;}Dispcnt=0;}}//T1中断**运行时间void Time_1() interrupt 3{TH1=0xDB;TL1=0xFF;RTime_cnt++;}/******配置文件Afx.h******/#ifndef _AFX_#define _AFX_typedef unsigned char uchar;typedef unsigned int uint;typedef unsigned long ulong;#endif/******IO配置文件Config.c******/#ifndef _Config_#define _Config_#include "Afx.h"#include <reg52.h>//显示定义sbit led=P3^2;//电机引脚定义sbit LMot_P=P2^2; sbit LMot_M=P2^3; sbit RMot_P=P2^0; sbit RMot_M=P2^1;#endif。
89c51单片机C语言编写的PWM程序PWM, 单片机, C语言, 程序, 编写分享到:新浪微博 QQ空间开心网人人网说明:本程序使用STC89C52RC单片机,22.1184MHz晶振,要使用本程序需要自己修改,我是用来控制直流电机的,外接了L298驱动电路,有问题或意见请回复,谢谢^_^#include "reg52.H"#include "MyType.h"//=============L298端口定义===============sbit ENA = P3^6;?//左轮驱动使能sbit IN1 = P0^3;?//左轮黑线(-)sbit IN2 = P0^4;?//左轮红线(+)sbit IN3 = P0^5;?//右轮红线(-)sbit IN4 = P0^6;?//右轮黑线(+)sbit ENB = P3^7;?//右轮驱动使能//=============PWM================#define PWM_COUST 100?//PWM细分等份uchar MOTO_speed1;??//左边电机转速uchar MOTO_speed2; ??//右边电机转速uchar PWM_abs1;???//左边电机取绝对值后占空比uchar PWM_abs2;???//左边电机取绝对值后占空比?uchar PWM_var1=20;??//左边电机直走速度(不同的电机,此参数不同)uchar PWM_var2=20;??//右边电机直走速度uchar PWMAnd = 0;??//PWM自增变量/****************************************************************** 名称:motor(char speed1,char speed2);功能:同时调节电机的转速参数:speed1:电机1的PWM值;speed2:电机2的PWM值?? speed>0.正转;speed<0.反转(-100~100)调用:extern int abs(int val); 取绝对值返回:/******************************************************************/ void motor(char speed1,char speed2){??//==============左边电机=============?if (speed1>0)??{??IN1 =0;IN2 =1;//正转??}???else if (speed1<0)??{??IN1 =1;IN2 =0;//反转??}?//==============右边电机=============?if (speed2>0)??{??IN3 =1;IN4 =0;//正转??}?else if (speed2<0)??{??IN3 =0;IN4 =1;//反转??}}/******************************************************************名称:motor_PWM();功能:PWM占空比输出参数:无调用:无返回:无/******************************************************************/void motor_PWM (){?uchar PWM_abs1;?uchar PWM_abs2;?PWM_abs1=MOTO_speed1;?PWM_abs2=MOTO_speed2;?if (PWM_abs1>PWMAnd) ENA=1;??? //左边电机占空比输出??else ENA=0;?if (PWM_abs2>PWMAnd) ENB=1;??? //右边电机占空比输出??else ENB=0;?if (PWMAnd>=PWM_COUST) PWMAnd=0;? //PWM计数清零??else PWMAnd+=1;}???/******************************************************************名称:void TIME_Init ();功能:定时器初始化指令:调用:无返回:无/******************************************************************/void TIME_Init ()?{//=========定时器T2初始化 PWM==================?T2CON = 0x00;? ?T2MOD = 0x00;? ?RCAP2H = 0xff;?//定时0.1ms? ?RCAP2L = 0x47;? ?TH2 = 0xff;? ?TL2 = 0x47;?ET2 = 1;??//定时器2中断开?TR2 = 1;??//PWM定时器关,PWM周期为10ms?}/******************************************************************名称:void PWM_Time2 () interrupt 5功能:T2中断,PWM控制参数:调用:motor_PWM();//PWM占空比输出返回:/******************************************************************/?void PWM_Time2 () interrupt 5{? ?TR2 = 0;?TF2 = 0;?ET2 = 0;?//定时器0中断禁止?motor_PWM();//PWM占空比输出?ET2 = 1;?//定时中断0开启?TR2 = 1;}main(){TIME_Init ()?;motor(50,50);//左右电机的转速都是50}。
#include<lm3sxxx.h>unsigned long TheSysClock=12000000UL;#include"lcdinit.h"#define PB0_PWM2 GPIO_PIN_0 //PWM2、产生正转信号#define PB1_PWM3 GPIO_PIN_1 //PWM3、产生反转信号#define KEY_PERIPH SYSCTL_PERIPH_GPIOC#define KEY_PORT GPIO_PORTC_BASE#define KEY1_PIN GPIO_PIN_4 //正反转切换#define KEY2_PIN GPIO_PIN_5 //2档#define KEY3_PIN GPIO_PIN_6 //1档#define KEY4_PIN GPIO_PIN_7 //制动unsigned int flag,value,D,S;/*****************************************************************************/ void clockInit(void){SysCtlLDOSet(SYSCTL_LDO_2_50V); // 设置LDO输出电压SysCtlClockSet(SYSCTL_USE_OSC | // 系统时钟设置SYSCTL_OSC_MAIN | // 采用主振荡器SYSCTL_XTAL_6MHZ | // 外接6MHz晶振SYSCTL_SYSDIV_1); // 不分频TheSysClock = SysCtlClockGet(); // 获取当前的系统时钟频率}void GPIO_Port_C_ISR(void){unsigned long ulStatus;ulStatus = GPIOPinIntStatus(GPIO_PORTC_BASE, true); // 读取中断状态GPIOPinIntClear(GPIO_PORTC_BASE, ulStatus); // 清除中断状态,重要if (ulStatus & KEY1_PIN) // 如果PC4的中断状态有效{ SysCtlDelay(200); //消除按键抖动flag=~flag;}if (ulStatus & KEY2_PIN) // 如果PC5的中断状态有效{ SysCtlDelay(200);value=50;S=2; //S=2表示高速}if (ulStatus & KEY3_PIN) // 如果PC6的中断状态有效{ SysCtlDelay(200);value=200;S=1; //S=1表示低速}if (ulStatus & KEY4_PIN) // 如果PC7的中断状态有效{ SysCtlDelay(200);value=300;S=0; //S=0表示制动}}/***************************************************************************/ void lcd_disp(){ lcd_pos(0,0);lcd_strwdat("Direct Is:"); //第一行显示正反转lcd_pos(0,14);lcd_write(1,D); //LCD写数据lcd_pos(1,0);lcd_strwdat("Now Speed Is:");//第二行显示转速的档位lcd_pos(1,14);lcd_write(1,S); //LCD写数据}void flag_1() //反转{ PWMOutputState(PWM_BASE, PWM_OUT_3_BIT, true);PWMOutputState(PWM_BASE, PWM_OUT_2_BIT, false); //使能或禁止PWM的输出PWMGenPeriodSet(PWM_BASE, PWM_GEN_1, 300); // 设置PWM发生器1的周期PWMPulseWidthSet(PWM_BASE, PWM_OUT_3, value); // 设置PWM2输出的脉冲宽度D=0; //D=0表示反转}void flag_0(){ PWMOutputState(PWM_BASE, PWM_OUT_2_BIT, true); //正转PWMOutputState(PWM_BASE, PWM_OUT_3_BIT, false);PWMGenPeriodSet(PWM_BASE, PWM_GEN_1, 300); // 设置PWM发生器1的周期PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, value); // 设置PWM3输出的脉冲宽度D=1; //D=1表示正转}/***************************************************************************/ int main (void){lcd_init();clockInit();SysCtlPeripheralEnable (KEY_PERIPH); // 使能KEY所在的GPIO端口GPIOPinTypeGPIOInput(KEY_PORT, KEY1_PIN|KEY2_PIN|KEY3_PIN|KEY4_PIN);// 设置key1、key2、key3、key4为输入GPIOIntTypeSet(KEY_PORT, KEY1_PIN|KEY2_PIN|KEY3_PIN|KEY4_PIN, GPIO_LOW_LEVEL);// 设置KEY1、KEY2、KEY3、KEY4管脚的中断类型GPIOPinIntEnable(KEY_PORT, KEY1_PIN|KEY2_PIN|KEY3_PIN|KEY4_PIN);// 使能KEY1、KEY2、KEY3、KEY4所在管脚的中断IntEnable(INT_GPIOC); // 使能GPIOC端口中断SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // 使能PWM2和PWM3输出所在GPIOSysCtlPeripheralEnable(SYSCTL_PERIPH_PWM); // 使能PWM模块SysCtlPWMClockSet(SYSCTL_PWMDIV_1); // PWM时钟配置:不分频GPIOPinTypePWM(GPIO_PORTB_BASE, PB0_PWM2); // PB0配置为PWM功能GPIOPinTypePWM(GPIO_PORTB_BASE, PB1_PWM3); // PB1配置为PWM功能PWMGenConfigure(PWM_BASE, PWM_GEN_1, // 配置PWM发生器1:加减计数PWM_GEN_MODE_UP_DOWN |PWM_GEN_MODE_NO_SYNC);PWMOutputState(PWM_BASE, PWM_OUT_2_BIT, true); //初始化时flag=0、即电机初始化时是正转PWMOutputState(PWM_BASE, PWM_OUT_3_BIT, false);PWMGenPeriodSet(PWM_BASE, PWM_GEN_1, 300); // 设置PWM发生器1的周期PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, value); // 设置PWM3输出的脉冲宽度PWMGenEnable(PWM_BASE, PWM_GEN_1); // 使能PWM发生器1IntMasterEnable( ); // 使能处理器中断while(1){ SysCtlDelay(200);if(flag){ flag_1();lcd_disp();}else{ flag_0();lcd_disp();}}}/*****************************************************************************/。
pwm调速控制小车循迹壁障c程序#include< reg51.h >#define uchar unsigned char#define uint unsigned int#define MOTOR_C P1 //P1口作为电机的控制口。
//#define SIGNAL P3 //P3口的低两位为循迹传感器输入口。
#define SHELVES 10 //速度总档数。
#define BACK 0xfa //后退。
#define FORWARD 0xf5 //前进。
sbit senserr = P3^2; //(右)循迹。
sbit senserl = P3^3; //(左)循迹。
sbit hwf = P3^0; //(前)红外壁障传感器入口。
sbit hwb = P3^1; //(后)红外壁障传感器入口。
sbit PWM_R = P1^0; //右电机PWM输入口。
sbit PWM_L = P1^2; //左电机PWM输入口。
sbit PWM_HR = P1^1; //(后退)右电机。
sbit PWM_HL = P1^3; //(后退)左电机。
void timer0_init( void ); //定时器0初始化函数。
void timer1_init( void ); //定时器1初始化函数。
void right( void ); //前进右转弯函数。
void left( void ); //前进左转弯函数。
void forward( void ); //前进函数。
void hright(void); //后退右转函数。
void hleft(void); //后退左转函数。
void back(void); //后退函数。
uchar percent_l = 0; //(前进)左轮占空比。
uchar percent_r = 0; //(前进)右轮占空比。
uchar percent_hl = 0; //(后退)左轮占空比。
89c51单片机C语言编写的PWM程序PWM, 单片机, C语言, 程序, 编写分享到:新浪微博 QQ空间开心网人人网说明:本程序使用STC89C52RC单片机,22.1184MHz晶振,要使用本程序需要自己修改,我是用来控制直流电机的,外接了L298驱动电路,有问题或意见请回复,谢谢^_^#include "reg52.H"#include "MyType.h"//=============L298端口定义===============sbit ENA = P3^6;?//左轮驱动使能sbit IN1 = P0^3;?//左轮黑线(-)sbit IN2 = P0^4;?//左轮红线(+)sbit IN3 = P0^5;?//右轮红线(-)sbit IN4 = P0^6;?//右轮黑线(+)sbit ENB = P3^7;?//右轮驱动使能//=============PWM================#define PWM_COUST 100?//PWM细分等份uchar MOTO_speed1;??//左边电机转速uchar MOTO_speed2; ??//右边电机转速uchar PWM_abs1;???//左边电机取绝对值后占空比uchar PWM_abs2;???//左边电机取绝对值后占空比?uchar PWM_var1=20;??//左边电机直走速度(不同的电机,此参数不同)uchar PWM_var2=20;??//右边电机直走速度uchar PWMAnd = 0;??//PWM自增变量/****************************************************************** 名称:motor(char speed1,char speed2);功能:同时调节电机的转速参数:speed1:电机1的PWM值;speed2:电机2的PWM值?? speed>0.正转;speed<0.反转(-100~100)调用:extern int abs(int val); 取绝对值返回:/******************************************************************/ void motor(char speed1,char speed2){??//==============左边电机=============?if (speed1>0)??{??IN1 =0;IN2 =1;//正转??}???else if (speed1<0)??{??IN1 =1;IN2 =0;//反转??}?//==============右边电机=============?if (speed2>0)??{??IN3 =1;IN4 =0;//正转??}?else if (speed2<0)??{??IN3 =0;IN4 =1;//反转??}}/******************************************************************名称:motor_PWM();功能:PWM占空比输出参数:无调用:无返回:无/******************************************************************/void motor_PWM (){?uchar PWM_abs1;?uchar PWM_abs2;?PWM_abs1=MOTO_speed1;?PWM_abs2=MOTO_speed2;?if (PWM_abs1>PWMAnd) ENA=1;??? //左边电机占空比输出??else ENA=0;?if (PWM_abs2>PWMAnd) ENB=1;??? //右边电机占空比输出??else ENB=0;?if (PWMAnd>=PWM_COUST) PWMAnd=0;? //PWM计数清零??else PWMAnd+=1;}???/******************************************************************名称:void TIME_Init ();功能:定时器初始化指令:调用:无返回:无/******************************************************************/void TIME_Init ()?{//=========定时器T2初始化 PWM==================?T2CON = 0x00;? ?T2MOD = 0x00;? ?RCAP2H = 0xff;?//定时0.1ms? ?RCAP2L = 0x47;? ?TH2 = 0xff;? ?TL2 = 0x47;?ET2 = 1;??//定时器2中断开?TR2 = 1;??//PWM定时器关,PWM周期为10ms?}/******************************************************************名称:void PWM_Time2 () interrupt 5功能:T2中断,PWM控制参数:调用:motor_PWM();//PWM占空比输出返回:/******************************************************************/?void PWM_Time2 () interrupt 5{? ?TR2 = 0;?TF2 = 0;?ET2 = 0;?//定时器0中断禁止?motor_PWM();//PWM占空比输出?ET2 = 1;?//定时中断0开启?TR2 = 1;}main(){TIME_Init ()?;motor(50,50);//左右电机的转速都是50}。
直流电机PWM调速程序(C语言)#include<reg52.h>//头文件#define ulong unsigned long//关键字宏定义 #define uchar unsigned charsbit motor_l_a=P0^2;//直流电机控制线接口定义 sbit motor_l_b=P0^3;// sbit motor_r_a=P0^0;// sbit motor_r_b=P0^1;// sbit motor_l_en=P0^4;// sbit motor_r_en=P0^5;////*****************变量定义***************************//ulong delay_flag=0;//用于较精确延时的变量 uchar pwm=0;//定时器0中断服务程序中的计数变量 uchar PWM_L=0,PWM_R=0;//***************函数声明******************************//void init_time0();//定时器0初始化函数 void motor_run(uchardirect,uchar speed_l,uchar speed_r);//直流电机控制函数.direct 控制方向,speed分别控制两个电机转速//***************主函数********************************//void main(){uchar i;//用于直流电机循环工作中的变量init_time0();//调用初始化函数while(1){for(i=0;i<11;i++)//直流电机正向加速{motor_run(1,i,i);delay_flag=20000;while(delay_flag);}for(i=10;i>0;i--)//直流电机反向减速{motor_run(0,i,i);delay_flag=20000;while(delay_flag);}}}void time0_pwm() interrupt 1//定时器0中断服务程序 { //**********************直流电机PWM调速部分***************************//pwm++;if(pwm==10)//设置PWM调速周期为1ms。
单片机PWM温控C语言程序部分代码#include <reg52.h>#include <at89x52.h>#include <keyscan.h>extern void scan_full(void);extern unsigned char key_scan(void);extern bit key_ok;unsigned char pwm_set,key_value;unsigned char count;sbit PWM=P3^6; //将PWM定义为P3口的第六位?bit up,down,set_flag;unsigned char code BCD[]={0x3f,0x06,0x5b,0x4f, //此处是将0-F转换成0x66,0x6d,0x7d,0x07, //相应的BCD码0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};void delay1(unsigned char t){while(t--);}void pwm(void) interrupt 5//定时器2产生PWM波形{TF2=0; //定时器2的溢出标志要软件清除,//但当RCLK或TCLK为1时由硬件清除if((count>=pwm_set)&amt;&amt;(count<10))PWM=1;elsePWM=0;count++;if(count==10)count=0x00;}void key_pwm(unsigned char x)//把键值转化为PWM设置值{switch(x) //把矩阵键盘转化为独立键盘{case 1:up=1;break;case 2:down=1;break;case 3:set_flag=!set_flag;break;default:break;}//设置PWM参数:pwm_setif(up&amt;&amt;set_flag){pwm_set++;up=0;if(pwm_set>=10)pwm_set=0x00;}if(down&amt;&amt;set_flag){pwm_set--;down=0;if(pwm_set==0xff) //减到-1?pwm_set=9;}if(!set_flag){up=0;down=0;}}void main(void){TH2=0xb1; //定时20MSTL2=0xe0;RCAP2H=0xb1;//定时器2溢出会把该单元内容送到TH2和TL2 RCAP2L=0xe0;EA=1;ET2=1;TR2=1;while(1){scan_full(); //看是否有键按下if(key_ok) //有键按下,则判断到底是哪个键按下{key_value=key_scan();//键值送key_value暂存P0=~BCD[key_value]; /*此三句是将键值显示出来*/P2=0xfe;delay1(200);key_pwm(key_value); //调用键值转PWM设置参数函数key_value=0x00; //清除键值,以免一次按下,多次响应}P0=~BCD[pwm_set]; /***此三句是将pwm_set值显示出来*/P2=0xfd;delay1(200);}}#include <reg52.h>//#include <at89x52.h>//unsigned char code BCD[]={0x3f,0x06,0x5b,0x4f, //此处是将0-F转换成//相应的BCD码 :// 0x66,0x6d,0x7d,0x07,// 0x7f,0x6f,0x77,0x7c,// 0x39,0x5e,0x79,0x71};//unsigned char code KEY[]={0x00,0x00,0x01,0x02,0x03,//此处是为使程序通用,当键值不是按// 0x04,0x05,0x06,0x07,//这个排列时,把此表更改即可// 0x08,0x09,0x0a,0x0b,//最前面的那个0x00是为了查表方便,// 0x0c,0x0d,0x0e,0x0f};//因为键值是从1开始的sfr key_port=0x90; //定义P1口为键盘扫描口bit key_ok=0; //有键按下的标志/*************延时子程序*****************调用一次用时18微秒,t每加1,用时增加6微秒*/void delay(unsigned char t){while(t--);}unsigned char r_left(unsigned char x)//循环左移一位{x<<=1;x++;return(x);}/*************粗判有无键按下**************有键按下则将key_ok置1************/void scan_full(void){unsigned char temp;key_port=0xf0; //低半字节为行线,高半字节为列线temp=P1;if(temp!=0xf0)key_ok=1;elsekey_ok=0;}/************键盘扫描程序*****************************功能:返回键值,当无键按下时,返回0*************/unsigned char key_scan(void){unsigned char temp,count=0x01,key_value;//按键返回值unsigned char x_scan=0xfe,y_scan=0xef;//行、列扫描码unsigned char i,j,y; //行数和列数while(1){scan_full(); //粗判是否有键按下if(key_ok==1){key_ok=0;delay(200); //延时去抖动scan_full(); //再次粗判是否有键按下if(key_ok==1){for(i=0;i<4;i++) //扫描4行{key_port=x_scan;for(j=0;j<4;j++) //每行4列{temp=key_port;temp=temp&amt;0xf0;y=y_scan&amt;0xf0;if(temp==y){while(key_ok!=0)//等待按键松开{scan_full();}key_value=count;return(key_value);//找到键值,马上返回}else{count++;y_scan=r_left(y_scan);}}y_scan=0xef; //扫描完一列,重新对列扫描量赋初值x_scan=r_left(x_scan);//行扫描码左移一位,扫描下一行}}}return(key_value);//没键按下,返回0}}//unsigned char key(void)//{// unsigned char x;// unsigned char y;// x=key_scan();// return(x);// y=KEY[x];// return y;//}。
PWM调速的C语言程序编写关于PWM的原理在上一篇文章中已经说的很详细了,现在就细说一下pwm C语言程序的编写。
C语言中PWM的编写有这么几种方法;一、用普通的I/O口输出的PWM ,二、使用定时计数器编写,三、就是使用片内PWM了。
1 先说使用普通的I\O口编写PWM程序了。
使用I/O口输出PWM波形你必须首先明白PWM他的实质是:调制占空比,占空比就是波形中高电平的长度与整个波长的比值。
我们写C语言的目的是写PWM波形的一个周期。
在这个周期内高低电平的比值是可以改变的。
这也就符合了PWM的原意脉宽调制。
即高电平的宽度的调制。
当然了PWM他也可用于改变频率,我们这里只先说他改变脉宽。
一旦我们的C语言程序写完那么他产生的PWM波形的频率就一定了。
(也可写频率变化的PWM,难度有点大)一般我们控制使用1K到10K的PWM波进行控制。
当然了你也可在要求不是很高的地方使用频率更低的PWM波。
比如在飞思卡尔智能车比赛中我们学校使用的PWM波频率只有600HZ.我们要改变一个PWM波周期内的高电平的宽度显然需要将一个PWM波的周期分成单片机可以控制的N个小的周期,N的取值越大你的调速等级越高,但产生的PWM频率就越低。
我们下面以实现100级调速为例编写PWM程序。
先写出程序再慢慢给大家分析void pwm (uchar x,uint y) //X 为占空比Y为函数使用时间{ uint i,j,a,b;for(i=y;i>0;i--) //定时外函数{for(j=7;j>0;j--) //定时内函数{for(a=y;a>0;a--) //PWM波高电平宽度{PORTA=0X01;}for(b=100-y;b>0;b--) //PWM低电平宽度{PORTA=0X00;}}}}这个程序够简单吧轻松的实现AVR单片机的PA.0口输出7KHZ左右的PWM脉冲你可以将PORTA=0X01;改为P1.0=0X01;就可以移植到51单片机上了为什么使用参数Y定时是因为用普通I/O口控制它的开关没有使用定时器编写的灵活。
//T0产生双路PWM信号,L298N为直流电机调速,接L298N时相应的管脚上最好接上10K 的上拉电阻。
/* 晶振采用12M,产生的PWM的频率约为100Hz */#include<reg51.h>#include<math.h>#define uchar unsigned char#define uint unsigned intsbit en1=P3^4; /* L298的Enable A */sbit en2=P3^5; /* L298的Enable B */sbit s1=P1^0; /* L298的Input 1 */sbit s2=P1^1; /* L298的Input 2 */sbit s3=P1^3; /* L298的Input 3 */sbit s4=P1^2; /* L298的Input 4 */sbit R=P2^0;sbit C=P2^1;sbit L=P2^2;sbit key=P1^4;uchar t=0; /* 中断计数器*/uchar m1=0; /* 电机1速度值*/uchar m2=0; /* 电机2速度值*/uchar tmp1,tmp2; /* 电机当前速度值*//* 电机控制函数index-电机号(1,2); speed-电机速度(0-100) */ void motor(uchar index, char speed){if(speed<=100){if(index==1) /* 电机1的处理*/{m1=abs(speed); /* 取速度的绝对值*/s1=1;s2=0;}if(index==2) /* 电机2的处理*/{m2=abs(speed); /* 电机2的速度控制*/ s3=1;s4=0;}}}void Back(void){s1=0;s2=1;s3=1;s4=0;}void GO(void){s1=1;s2=0;s3=1;s4=0;}void TL(void) {s1=1;s2=0;s3=0;s4=1;}void TR(void) {s1=0;s2=1;s3=1;s4=0;}void STOP(void){s1=1;s2=1;s3=1;s4=1;}void delay(uint j) /* 简易延时函数*/ {for(j;j>0;j--);}void main(){uchar i=0,j=0;TMOD=0x02; /* 设定T0的工作模式为2 ,8位自动重置定时器,没过几个机器周期,计数器加一*/TH0=0x9B; /* 装入定时器的初值,计数100次溢出*/TL0=0x9B; /*装入时间常数*/EA=1; /* 开中断*/ET0=1; /* 定时器0允许中断*/ TR0=1; /* 启动定时器0 */ while(1){if(key==1){/* 电机实际控制演示*/if(i<=100) // 正转加速{motor(1,i);motor(2,i);delay(5000);i++;}else{GO();}}else{EA=0;while(1){if((L|C|R)==0) STOP();if(L&R)GO();if(L==0){while(C){TL();}}if(R==0){while(C){TR();}}}}}}void timer0() interrupt 1 /* T0中断服务程序*/ {if(t==0) /* 1个PWM周期完成后才会接受新数值*/ { tmp1=m1;tmp2=m2;}if(t<tmp1) en1=1; else en1=0; /* 产生电机1的PWM信号*/ if(t<tmp2) en2=1; else en2=0; /* 产生电机2的PWM信号*/ t++;if(t>=100) t=0; /* 1个PWM信号由100次中断产生*/}。
PWM调速的C语言程序编写
关于PWM的原理在上一篇文章中已经说的很详细了,现在就细说一下pwm C语言程序的编写。
C语言中PWM的编写有这么几种方法;一、用普通的I/O口输出的PWM ,二、使用定时计数器编写,三、就是使用片内PWM了。
先说使用普通的I\O口编写PWM程序了。
使用I/O口输出PWM波形你必须首先明白PWM他的实质是:调制占空比,占空比就是波形中高电平的长度与整个波长的比值。
我们写C语言的目的是写PWM波形的一个周期。
在这个周期内高低电平的比值是可以改变的。
这也就符合了PWM的原意脉宽调制。
即高电平的宽度的调制。
当然了PWM他也可用于改变频率,我们这里只先说他改变脉宽。
一旦我们的C语言程序写完那么他产生的PWM波形的频率就一定了。
(也可写频率变化的PWM,难度有点大)一般我们控制使用1K到10K的PWM波进行控制。
当然了你也可在要求不是很高的地方使用频率更低的PWM波。
比如在飞思卡尔智能车比赛中我们学校使用的PWM波频率只有600HZ.
我们要改变一个PWM波周期内的高电平的宽度显然需要将一个PWM波的周期分成单片机可以控制的N个小的周期,N的取值越大你的调速等级越高,但产生的PWM频率就越低。
我们下面以实现100级调速为例编写PWM程序。
先写出程序再慢慢给大家分析
void pwm (uchar x,uint y) //X 为占空比 Y为函数使用时间
{ uint i,j,a,b;
for(i=y;i>0;i--) //定时外函数
{
for(j=7;j>0;j--) //定时内函数
{
for(a=y;a>0;a--) //PWM波高电平宽度
{
PORTA=0X01;
}
for(b=100-y;b>0;b--) //PWM低电平宽度
{
PORTA=0X00;
}
}
}
}
这个程序够简单吧轻松的实现AVR单片机的PA.0口输出7KHZ左右的PWM脉冲
你可以将PORTA=0X01;改为P1.0=0X01;就可以移植到51单片机上了
为什么使用参数Y定时是因为用普通I/O口控制它的开关没有使用定时器编写的灵活。
如果这不符合你的需要你可以不使用时间参数Y控制他的开关,只要去掉关于Y的部分利用控制I/O口的方向来控制它的使用
上面的程序参数如下
在mega16单片机上使用 8M晶振
一个PWM脉冲大约128μs
循环7次是940ms 所以输出PWM脉冲频率是7KHZ左右
注意:我使用时精度要求不高所以没有考虑for语句运行时花费的时间故实际占空比略低,但误差是很小的。
需要高精度的朋友可以自己做修改。