PWM调速的C语言程序编写非常简单
- 格式:docx
- 大小:9.75 KB
- 文档页数:3
[转]单片机C语言编程模板(PWM脉宽调制)修改浏览权限| 删除∙- MCS-51系列单片机C语言编程PWM脉宽调制器程序模板∙- 适用于STC系列内嵌PWM的单片机产品(以STC12C2052为例)- 以PWM控制LED亮度实验电路为例/********************************************************************************************* 函数名:PWM初始化函数调用:PWM_init();参数:无返回值:无结果:将PCA初始化为PWM模式,初始占空比为0备注:需要更多路PWM输出直接插入CCAPnH和CCAPnL即可/**********************************************************************************************/ void PWM_init (void){CMOD=0x02; //设置PCA定时器CL=0x00;CH=0x00;CCAPM0=0x42; //PWM0设置PCA工作方式为PWM方式(0100 0010)CCAP0L=0x00; //设置PWM0初始值与CCAP0H相同CCAP0H=0x00; // PWM0初始时为0//CCAPM1=0x42; //PWM1设置PCA工作方式为PWM方式(使用时删除//)//CCAP1L=0x00; //设置PWM1初始值与CCAP0H相同//CCAP1H=0x00; // PWM1初始时为0//CCAPM2=0x42; //PWM2设置PCA工作方式为PWM方式//CCAP2L=0x00; //设置PWM2初始值与CCAP0H相同//CCAP2H=0x00; // PWM2初始时为0//CCAPM3=0x42; //PWM3设置PCA工作方式为PWM方式//CCAP3L=0x00; //设置PWM3初始值与CCAP0H相同//CCAP3H=0x00; // PWM3初始时为0CR=1; //启动PCA定时器}/**********************************************************************************************//********************************************************************************************* 函数名:PWM0占空比设置函数调用:PWM0_set();参数:0x00~0xFF(亦可用0~255)返回值:无结果:设置PWM模式占空比,为0时全部高电平,为1时全部低电平备注:如果需要PWM1的设置函数,只要把CCAP0L和CCAP0H中的0改为1即可/**********************************************************************************************/ void PWM0_set (unsigned char a){CCAP0L= a; //设置值直接写入CCAP0LCCAP0H= a; //设置值直接写入CCAP0H}/**********************************************************************************************/ - 程序模块/********************************************************************************************* 程序名:PWM模块调试程序(仅实验用)编写人:杜洋编写时间:2009年7月22日硬件支持:STC12C2052 12MHz接口说明:LED灌电流接P3.7接口(PWM0)修改日志:NO.1-/********************************************************************************************* 说明:/*********************************************************************************************/ #include<STC12C2052AD.H> //头文件/********************************************************************************************* 函数名:PWM初始化函数调用:PWM_init();参数:无返回值:无结果:将PCA初始化为PWM模式,初始占空比为0备注:需要更多路PWM输出直接插入CCAPnH和CCAPnL即可/**********************************************************************************************/ void PWM_init (void){CMOD=0x02; //设置PCA定时器CL=0x00;CH=0x00;CCAPM0=0x42; //PWM0设置PCA工作方式为PWM方式(0100 0010)CCAP0L=0x00; //设置PWM0初始值与CCAP0H相同CCAP0H=0x00; // PWM0初始时为0//CCAPM1=0x42; //PWM1设置PCA工作方式为PWM方式(使用时删除//)//CCAP1L=0x00; //设置PWM1初始值与CCAP0H相同//CCAP1H=0x00; // PWM1初始时为0//CCAPM2=0x42; //PWM2设置PCA工作方式为PWM方式//CCAP2L=0x00; //设置PWM2初始值与CCAP0H相同//CCAP2H=0x00; // PWM2初始时为0//CCAPM3=0x42; //PWM3设置PCA工作方式为PWM方式//CCAP3L=0x00; //设置PWM3初始值与CCAP0H相同//CCAP3H=0x00; // PWM3初始时为0CR=1; //启动PCA定时器}/**********************************************************************************************//********************************************************************************************* 函数名:PWM0占空比设置函数调用:PWM0_set();参数:0x00~0xFF(亦可用0~255)返回值:无结果:设置PWM模式占空比,为0时全部高电平,为1时全部低电平备注:如果需要PWM1的设置函数,只要把CCAP0L和CCAP0H中的0改为1即可/**********************************************************************************************/ void PWM0_set (unsigned char a){CCAP0L= a; //设置值直接写入CCAP0LCCAP0H= a; //设置值直接写入CCAP0H}/**********************************************************************************************//********************************************************************************************* 函数名:主函数调用:无参数:无返回值:无结果:程序开始处,无限循环备注:/**********************************************************************************************/ void main (void){PWM_init(); //PWM初始化PWM0_set(0x10); //设置PWM占空比while(1){//无限循环程序}}/**********************************************************************************************/ /************************************************************** 杜洋工作室/*************************************************************/- 应用实例- 使用说明。
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口控制它的开关没有使用定时器编写的灵活。
#include<>#define uchar unsigned char#define uint unsigned int/* 端口定义*/sbit in1=P1^0;sbit in2=P1^1;sbit jian=P2^0;sbit jia=P2^1;sbit dir=P2^2;sbit run=P2^3;sbit inter_0=P3^2;sbit inter_1=P3^3;#define LCD_data P0 //数据口sbit LCD_RS = P2^7; //寄存器选择输入sbit LCD_RW = P2^6; //液晶读/写控制sbit LCD_EN = P2^5; //液晶使能控制sbit LCD_PSB = P2^4; //串/并方式控制uchar t10,t1,ce,cj,s1=0,pl=10;uchar zi[]={"电机转速:"};uchar num[3];uint nums=0,speed,k=1200;void delay_1ms(uchar x){uchar i,j;for(j=0;j<x;j++)for(i=0;i<110;i++);}/*******************************************************************/ /**//*写指令数据到LCD*//*RS=L,RW=L,E=高脉冲,D0-D7=指令码。
*//**//*******************************************************************/ void write_cmd(uchar cmd){LCD_RS = 0;LCD_RW = 0;LCD_EN = 0;P0 = cmd;delay_1ms(5);LCD_EN = 1;delay_1ms(5);LCD_EN = 0;}/*******************************************************************/ /**//*写显示数据到LCD*//*RS=H,RW=L,E=高脉冲,D0-D7=数据。
PWM电机调速程序*******************************************************************/ /* 程序名:PWM直流电机调速 *//* 晶振:11.00592 MHz CPU型号:AT89C51 *//* 直流电机的PWM波控制,可以直接的调速从0到20级的调速 *//*****************************************************************/ #include<reg51.h>#define TH0_TL0 (65536-1000)//设定中断的间隔时长unsigned char count0 = 50;//低电平的占空比unsigned char count1 = 0;//高电平的占空比bit Flag = 1;//电机正反转标志位,1正转,0反转sbit Key_add=P2 ^ 0; //电机减速sbit Key_dec=P2 ^ 1; //电机加速sbit Key_turn=P2 ^ 2; //电机换向sbit PWM1=P2^6;//PWM 通道 1,反转脉冲sbit PWM2=P2^7;//PWM 通道 2,正转脉冲unsigned char Time_delay;/************函数声明**************/void Delay(unsigned char x);void Motor_speed_high(void);void Motor_speed_low(void);void Motor_turn(void);void Timer0_init(void);/****************延时处理**********************/void Delay(unsigned char x){Time_delay = x;while(Time_delay != 0);//等待中断,可减少PWM输出时间间隔}/*******按键处理加pwm占空比,电机加速**********/void Motor_speed_high(void)//{if(Key_add==0)Delay(10);if(Key_add==0){count0 += 5;if(count0 >= 100){count0 = 100;}}while(!Key_add);//等待键松开}}/******按键处理减pwm占空比,电机减速*****/ void Motor_speed_low(void){if(Key_dec==0){Delay(10);if(Key_dec==0){count0 -= 5;if(count0 <= 0){count0 = 0;}}while(!Key_dec );}}/************电机正反向控制**************/ void Motor_turn(void){if(Key_turn == 0){Delay(10);if(Key_turn == 0){Flag = ~Flag;}while(!Key_turn);}/***********定时器0初始化***********/void Timer0_init(void){TMOD=0x01; //定时器0工作于方式1TH0=TH0_TL0/256;TL0=TH0_TL0%256;TR0=1;ET0=1;EA=1;}/*********主函数********************/void main(void){Timer0_init();while(1){Motor_turn();Motor_speed_high();Motor_speed_low();}}/**************定时0中断处理******************/ void Timer0_int(void) interrupt 1 using 1{TR0 = 0;//设置定时器初值期间,关闭定时器TL0 = TH0_TL0 % 256;TH0 = TH0_TL0 / 256 ;//定时器装初值TR0 = 1;if(Time_delay != 0)//延时函数用{Time_delay--;}if(Flag == 1)//电机正转{PWM1 = 0;if(++count1 < count0)PWM2 = 1;}elsePWM2 = 0;if(count1 >= 100){count1=0;}}else //电机反转{PWM2 = 0;if(++count1 < count0){PWM1 = 1;}elsePWM1 = 0;if(count1 >= 100){count1=0;}}}//-----------------------------------------------------------------------------#include <c8051f330.h> // SFR declarations#include <math.h>// Function Prototypes//-----------------------------------------------------------------------------#define CMD_RESET 0xA4 //HD7279复位#define DECODE1 0xc8 //方式0译码sbit cs=P1^3;sbit clk=P1^2;sbit dat=P1^1;sbit key=P1^0;sbit led_D1003=P0^7;sbit sw1=P1^7;sbit sw2=P1^6;sbit sw3=P1^5;sbit sw4=P1^4;void long_delay(void); //延时函数void short_delay(void);void delay10ms(unsigned char);void write7279(unsigned char,unsigned char); //HD7279写指令void send_byte(unsigned char);void delay(unsigned char);void disp1(unsigned int);void OSCILLATOR_Init (void);void PORT_Init (void);void PCA0_Init (void);void Timer0_Init(void);void Ext_Interrupt_Init (void);//-----------------------------------------------------------------------------// Global Variables//-----------------------------------------------------------------------------//-----------------------------------------------------------------------------// main() Routine//-----------------------------------------------------------------------------unsigned int CEX0_Compare_Value; // Holds current PCA compare valueunsigned int tmr,Speed_evaluate;unsigned char num,num1,num2,num3,a;unsigned int Speed,pi,Speed2;unsigned int Speed1[10];typedef struct {double SetPoint; /* 设定目标Desired Value */double Proportion; /* 比例常数Proportional Const */double Integral; /* 积分常数Integral Const */double Derivative; /* 微分常数Derivative Const */double LastError; /* 前一项误差*/double PrevError; /* 前第二项误差*/double SumError; /* 误差和*/} PID;double PIDCalc( PID *pp, double NextPoint ){double dError,Error,Pout;Error = pp->SetPoint - NextPoint; /* */pp->SumError += Error; /* /dError = pp->LastError - pp->PrevError; /* */pp->PrevError = pp->LastError;pp->LastError = Error; /* */Pout= pp->Proportion * Error + pp->Integral * pp->SumError +pp->Derivative * dError ;if(Pout>1100)Pout=1000;if(Pout<100)Pout=100;return (Pout);}PID sPID; //定义PID结构体变量double rOut; //PID响应输出unsigned char rIn; //设置PID反馈值double x;double sumout;unsigned char dd;//设置PID输出void main (void){sPID.Proportion = 0.44; //设置PsPID.Integral = 0.70; //设置IsPID.Derivative = 0.0; //设置D//sPID.SetPoint = CEX0_Compare_Value;//sPID.SetPoint = CEX0_Compare_Value; //设置PID输出PCA0MD = 0x00; // Disable watchdog timerled_D1003=0;PORT_Init (); // Initialize crossbar and GPIOOSCILLATOR_Init (); // Initialize oscillatorPCA0_Init (); // Initialize PCA0IP=0x82; //定时器中断0高于外部中断0Timer0_Init();Ext_Interrupt_Init ();for (tmr=0;tmr<0x2000;tmr++);send_byte(CMD_RESET);//HD7279复位// Globally enable interruptsEA = 1;sPID.SetPoint=70;while (1){delay10ms(100);//键盘程序 -------------------------------------------------------------if(sw1==0) //按键1是否按下{if(sw1==0)//再次检查按键{num++; //若按键按下,num加1if(num==1) //到9归0{num=0;}while(sw1==0);//按键释放}// delay10ms(100);}write7279(DECODE1+4,num); //将num写入HD7279第1位 delay10ms(1);if(sw2==0){if(sw2==0){num1++;if(num1==2){num1=0;}while(!sw2);}// delay10ms(100);}write7279(DECODE1+5,num1);//将num1写入HD7279第2位delay10ms(1);if(sw3==0){if(sw3==0){num2++;if(num2==10){num2=0;}while(!sw3);}// delay10ms(100);}write7279(DECODE1+6,num2);//将num1写入HD7279第2位delay10ms(1);if(sw4==0){if(sw4==0){num3++;if(num3==10){num3=0;}while(!sw4);}// delay10ms(100);}write7279(DECODE1+7,num3);//将num1写入HD7279第2位delay10ms(1);Speed_evaluate=num*1000+num1*100+num2*10+num3;sPID.SetPoint=Speed_evaluate;//控制程序-----------------------------------------------------------------//---------------------------------------------------------------------------}}void OSCILLATOR_Init (void){OSCICN = 0x83; // Set internal oscillator torun// at its maximum frequencyCLKSEL = 0x00;}void PORT_Init (void){XBR0 = 0x00;XBR1 = 0x41;// Enable crossbar and weak pull-upsP0MDOUT |= 0x10; // Set CEX0 (P0.4) to push-pull P0SKIP |=0x0F; //P1SKIP = 0x00;P1MDOUT= 0x0f;}void PCA0_Init (void){PCA0CN = 0x00; // Stop counter; clear allflagsPCA0MD = 0x01; // Use Ettern ime basePCA0CPM0 = 0xCB; // Module 0 = 16-bit PWM modeand// enable Module 0 Match and Interrupt// Flags// Configure initial PWM duty cycle = 50%CEX0_Compare_Value = 65536 - (65536 * 0.15);PCA0CPL0 = (CEX0_Compare_Value & 0x00FF);PCA0CPH0 = (CEX0_Compare_Value & 0xFF00)>>8;EIE1 |= 0x10; // Enable PCA interrupts// Start PCA counterCR = 1;}void Ext_Interrupt_Init (void){TCON |= 0x05; // /INT 0 and /INT 1 are edge triggeredIT01CF = 0x10; // /INT0 active low; /INT0 on P0.0;// /INT1 active low; /INT1 on P0.1EX0 = 1; // Enable /INT0 interrupts}void Timer0_Init(void){TH0 = 0 ; // Init Timer0 High registerTL0 = 0 ; // Init Timer0 Low registerTMOD |= 0x01; // Timer0 in 16-bit mode方式1CKCON |= 0x02; // Timer0 uses a 1:48 prescalerET0 = 1; // Timer0 interrupt enabledTCON|=0x10;// Timer0 ON}// PCA0_ISR//-----------------------------------------------------------------------------void PCA0_ISR (void) interrupt 11{CCF0 = 0; // Clear module 0 interrupt flag.PCA0CPL0 = (CEX0_Compare_Value & 0x00FF);PCA0CPH0 = (CEX0_Compare_Value & 0xFF00)>>8;}void Timer0_ISR (void) interrupt 1{int j,sum;TF0=0;// Clear interrupt flag.a++;if (a==4){Speed1[pi]=Speed;if(pi>=3){ EX0 = 0;for(j=0;j<=3;j++){sum=sum+Speed1[j];Speed2=sum/4;disp1(Speed2);Speed=0;pi=0;EX0 = 1;}a=0;sum=0;if(pi>=3)pi=0;elsepi++;TH0 = 0; // Reinit Timer0 High register TL0 = 0; // Reinit Timer0 Low registerif(abs( sPID.SetPoint-Speed2)<=5) {CEX0_Compare_Value=CEX0_Compare_Value;}else{rIn =Speed2;for(dd=0;dd<50;dd++)x=rIn;//x = 5.0 * (double)rIn / 256.0;rOut = PIDCalc ( &sPID,x );// sumout=rOut*256/5;if(rOut==100)sumout=0;elsesumout= (0.85/1000.0)*rOut;//CEX0_Compare_Value=CEX0_Compare_Value-sumout;CEX0_Compare_Value = 65536 - (65536 * ( sumout+0.15));}}else{TH0 = 0; // Reinit Timer0 High registerTL0 = 0; // Reinit Timer0 Low register}}void INT0_ISR (void) interrupt 0{IE0=0; // // Clear interrupt flag.Speed++;}void write7279(unsigned char cmd, unsigned char dta) {send_byte(cmd);send_byte(dta);}void send_byte( unsigned char out_byte){unsigned char i;cs=0;long_delay();for (i=0;i<8;i++){if (out_byte&0x80){dat=1;}else{dat=0;}clk=1;short_delay();clk=0;short_delay();out_byte=out_byte*2; }dat=0;}void long_delay(void){unsigned char i;for (i=0;i<0x30;i++);}void short_delay(void){unsigned char i;for (i=0;i<8;i++);}void delay10ms(unsigned char time) {unsigned char i;unsigned int j;for (i=0;i<time;i++){for (j=0;j<0x390;j++);}}void disp1(unsigned int date){unsigned char d0, d1, d2 , d3; d0=date / 1000;d1=(date-d0*1000)/100;d2=(date-d0*1000-d1*100)/10 ;d3= date-d0*1000-d1*100-d2*10;write7279(DECODE1,d0);delay10ms(1);write7279(DECODE1+1,d1);delay10ms(1);write7279(DECODE1+2,d2);delay10ms(1);write7279(DECODE1+3,d3);delay10ms(1);}。
pwm调试程序#include"iostm8s105c6.h"unsigned int note;//音符标志(全局变量)void GPIO_INIT(void);//io口初始化void TIM3_INIT(void);//键盘矩阵计时的tim3的初始化void keynote_real(void);//键盘确定音符程序void delay (unsigned int time);//延时函数void TIM1_INIT(unsigned int music);//TIM1初始化void TIM1_OC(void);//TIM1输出比较初始化int main( void ){TIM1_OC();//TIM1输出比较初始化TIM1_CCER1|=0x01;//TIM1比较输出使能输出note=4;TIM1_INIT(note);TIM1_CR1|=0X01;//TIM1定时器使能}/*********************TIM1初始化****************/ void TIM1_INIT(unsigned int music){unsigned int pscr;//TIM1_PSCR的数值unsigned int arr;//TIM1_ARR的数值switch(music){case 1:pscr=43,arr=44;break;//对应的DO的设置case 2:pscr=40,arr=41;break;//对应的RE的设置case 3:pscr=38,arr=39;break;//对应的MI的设置case 4:pscr=37,arr=38;break;//对应的FA的设置case 5:pscr=35,arr=36;break;//对应的SO的设置case 6:pscr=33,arr=34;break;//对应的LA的设置case 7:pscr=31,arr=32;break;//对应的SI的设置case 8:pscr=30,arr=31;break;//对应的DO'的设置}TIM1_PSCRH=0;//数字小于256,高八位都为0TIM1_PSCRL=(unsigned char)pscr;TIM1_ARRH=0;//数字小于256,高八位都为0TIM1_ARRL=(unsigned char)arr;TIM1_CR1=0X04;//TIM1_CR1=0000 0100B,边沿对齐模式,向上计数,但是计数器还没使能TIM1_CNTRH=0;TIM1_CNTRL=0;//使一开始的方波完整}/**************TIM1输出比较初始化***************/void TIM1_OC(void){PC_DDR|=0X02;PC_CR1|=0X02;PC_CR2=0X00;//初始化TIM1_CH1的引脚PC1为输出方式,由后级电路决定选择推挽输出TIM1_CCR1H=0X00;TIM1_CCR1L=0X16;//初始化TIM1_CCR输出比较寄存器,由于选择011模式,所以CCR1的值可以是随意TIM1_CCMR1=0X38;//初始化TIM1_CCMR1的CC1S为00;以及OC1M[2:0]位为011,而且实用预装载功能TIM1_BKR=0X80;//初始化刹车寄存器TIM1_CCER1&=0xfd;//高电平有效,但是还没有使能pwm输出}。
89c51单片机C语言编写的P W M程序(共3页)-本页仅作为预览文档封面,使用时请删除本页-89c51单片机C语言编写的PWM程序PWM, 单片机, C语言, 程序, 编写分享到:新浪微博 QQ空间开心网人人网说明:本程序使用STC89C52RC单片机,晶振,要使用本程序需要自己修改,我是用来控制直流电机的,外接了L298驱动电路,有问题或意见请回复,谢谢^_^#include ""#include ""转;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; //定时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语言程序编写关于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口控制它的开关没有使用定时器编写的灵活。
附录1. C语言源程序:#include"stdio.h"#include"myapp.h"#include"ICETEK-VC5502-EDU.h"#include"scancode.h"#include"lcd.h"#define CTRSTATUS (*(unsigned int * )0x608000) //port8000#define CTRLED (*(unsigned int * )0x608004) //port8004#define MCTRKEY (*(unsigned int * )0x608005) //port8005#define CTRCLKEY (*(unsigned int * )0x608006) //port8006#define CTRMOTORBSPEED (*(unsigned int * )0x608003)void InitMcBSP();void INTR_init( void );void InitForMotorB( void );void showparameters();void LCDPutString(unsigned int * pData,int x,int y,unsigned int nCharNumber,unsigned color);void PIDControl(int rk,int yk);void PrintParameters();//定时器分频参数#define T100 99 // 100个时钟周期中断一次#define T2Hz 20000 // 20000个时钟周期读取速度一次//工作变量usigned int uWork,uN,nCount,nCount1,nCount2,nCount3,nCount4;int nSSS,nJSSpeed,pwm1;int md,wc;unsigned int nScreenBuffer[30*128];float a=0.6f,b=0.2f,c=0.1f,duk;int ek,ek1,ek2,tz;int nInput;unsigned int *www=(unsigned int *)0x608003;Int m_nSpeed,m_bPCSet;// 主函数main(){unsigned char ccc;int speed[100],sp,lj;float ljh;int i,w1,w2,w3;unsigned int uWork1;unsigned int bWork1,*pWork;int breakflage;// 初始化工作变量for ( sp=0;sp<100;sp++ )speed[sp]=0;for ( sp=0;sp<1024;sp++ ) nScreenBuffer[sp]=0;sp=nSSS=nCount=nCount1=nCount2=nCount3=nCount4=nJSSpeed=0;nInput=tz=wc =0;ek=ek1=ek2=0;uN=40;md=70;pwm1=60;m_nSpeed=70;m_bPCSet=0;inputspeed=0;uWork1=0;breakflage=0;initemif();CLK_init();*(int*)0x400001=1;CREG=1; //使能外部总线接口InitCTR();CTRGR=0x80;CTRGR=0;CTRGR=0x80;LCDTurnoff();// 设置显示参数和内容LCDSetDelay(1); //设置延时等待参数LCDSetScreenBuffer(nScreenBuffer); // 显示缓冲区for (bWork=0,pWork=nScreenBuffer;bWork<30*128;bWork++,pWork++) (*pWork=0)LCDTurnOn();//打开显示LCDCLS();//清除显示内存LCDPutCString(str1,0,127,8,0);LCDPutCString(str2,0,111,2,1);LCDPutCString(str3,68,111,2,1);LCDPutCString(str4,68,79,2,1);LCDPutCString(str5,68,95,2,1);LCDPutCString(str6,0,95,2,1);LCDPutCString(str7,0,79,3,1);ShowParamctors();//参数显示InitMcBSP();INTR-init();InitForMotorB();While(!breakflage){if(nCount==0) //读取键盘标志{uWork=MCTRKEY;CTRCLKEY=0;Switch(uWork1){Casc 128;if(inputspecd!=0){Md=inputspecd;Inputspecd=0;LCDPutCString(numbers+104,104,79,1,1);LCDPutCString(numbers+104,112,79,1,1);LCDPutCString(numbers+104,120,79,1,1);LCDRefreshScreen();}break;case 64;breakflage=1;case 1;inputspeed=inputspeed+1break;case 2;inputspeed=inputspeed-1;break;case 4;inputspeed=inputspeed+10;break;case 8;inputspeed=inputspeed-10;break;}if(inputspeed>90){inputspeed=90;}if(inputspeed<0){inputspeed=0;}w1=inputspeed%1000/100;w2=inputspeed%100/10;w3=inputspeed%10; LCDPutString(numbers+w1*8,104,79,1,1);LCDPutString(numbers+w2*8,112,79,1,1);LCDPutString(numbers+w3*8,120,79,1,1);LCDRefreshScreen();}if(m-bPCSet){m-bPCSst=0;if (m-nSpeed>=0&&m-nSpeed<256){md=m-nSpeed;LCDPutCString(numbers+104,104,79,1,1); LCDPutCString(numbers+104,112,79,1,1); LCDPutCString(numbers+104,120,79,1,1); LCDRefreshScreen();printparameters();}}if(nJSSpeed==0) //读取速度标志{LED=1;nJSSpeed=0;ccc=CTRMOTORBSPEED; //读取端口速度计数ccc=ccc&0xff;nSSS=ccc;if(nSSS>=0 && nSSS<400) //合法性检测{speed(sp)=Nssssp++;sp%=33;}if(sp==0) //读取实际速度{lj=0;ljh=0;for(i=0;i<33;i++){if(speed(i)>=0&&speed(i)<400){ljh+=speed(i);lj++;}}nCount3++;nCount3%=3;if(nCount3==2){PIDControl(md,wc); //调用PID算法控制程序uN=100-pwml; //利用占空比调整控制Showparameters(); //显示各参数到LCD}CloseCTR();exit(0);}//PID算法控制子程序void PIDControl(int rk,int yk){ek=rk-yk;duk=a*ek+b*ek1+c*ek2; //计算控制输出ek2=ek1; ek1=ek;tz=(int)duk;pwm1+=tz; //计算当前占空比if(pwml<0) pwml=0;else if(pwml>99) pwml=99;}void interrupt Timer(){uWork=PCR1; //pwml输出if(nCont1>u N){uWork=4; //根据占空比设置FSR状态}else{uWork&=0x0fffb;}PCR1=uWork;//设置中断控制寄存器void INTR-init(void){asm(“BSET INTM”);IVPD=0x01;IVPH=0x01;IERO=0x10;DBIERO=0x10;IFRO=0xffff;asm(“BCLR INTM”);}void InitForMotorB(void){ioport unsigned int *GPTCTL1-0;ioport unsigned int *GPTPRD1-0;ioport unsigned int *GPTGCTL1-0;*GPTCTL1-0=0;*GPTPRD1-0=0x1d8;*GPTGCTL1-0=0x3;}//显示参数到LCDvoid ShowParameters(){int w1,w2,w3;w1=md%1000/100;w2=md%100/10,w3=md%10; LCDPutString(numbers+w1*8,36,111,1,1); LCDPutString(numbers+w2*8,44,111,1,1); LCDPutString(numbers+w3*8,52,111,1,1);if (ek>=0){LCDPutString(numbers+88,36,95,1,1);w3=((int)ek)%100;}else{LCDPutString(numbers+96,36,95,1,1);w3=((int)(-ek))%100;}for (j=0;j<16;j++,k<<=1){if (color==2) mcolor=2;else{mcolor=(pData(1*8+i)&k)(1):(0);if(color==0) mcolor=1-mcolor;}LCDPutPixel(x+1*8+I,y-j,mcolor);}int wwss;void PrintParameters(){wwcc=wc-md;printf(“测速(%3d) 设置(%3d) 误差(%+4d) PID调整量(%+3d) 占空比(%3d%%)\n”,wc,md,wwcc,tz,pwm1);}。
#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();}}}/*****************************************************************************/。
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语言实例,单片机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语言实例文件名:// 单片机PWM控制C语言实例功能: 用T2定时器产生PWM波,频率实调1khz // 单片机PWM控制C语言实例说明: 单片机AT89S52,晶振12MHZ;#include ""#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级可调(即每级差%),这样定时器T2每25us产生一个定时中断,每40次中断后进入下一个PWM波的周期。
PWM调速的C语言程序编写
关于PWM的原理在上一篇文章中已经说的很详细了,现在就细说一下pwmC语言程序的编写。
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程序。
????先写出程序再慢慢给大家分析
???voidpwm(ucharx,uinty)???//X为占空比Y为函数使用时间
{??uinti,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语句运行时花费的时间故实际占空比略低,但误差是很小的。
需要高精度的朋友可以自己做修改。
2.下面说如何使用定时/计数器来编写PWMC语言程序;。