有需要的可以直接下载
单片机源程序如下:
- //#include "iostm8s103k3.h"
- #include "iostm8s207r8.h"
- //STM8S207单片机; 连上仿真器后,ST-LINK-->Option Bytes: AFR5,右键-->Alternate Active,使PB0/PB1/PB2为PWM输出端口功能。
- //下载运行后,View-->Livewatch,观察PID控制参数的变化,观察LED1的亮度;
- //TIM2中断作为计时时间;PE0作为外中断输入;把外部频率信号与PE0连接,进行脉冲计数(频率测量)
- //开发板上用杜邦线把PB0与PD5连接起来;
- //单片机PC1(PWM输出)与焊的电路板PC1端子连接;电机编码器转速信号(黄线)与单片机PE0连接;
- //电机编码器供电正极(蓝线)接+5V;电机编码器供电负极(黑线)接GND;
- //电机本身供电正极(红线)接+12V,电机本身供电负极(白线)接焊的电路板的P1排针的第3脚(功率三极管集电极),
- //焊的电路板接线参考《直流电机PWM调速电路图》
- unsigned long pulsecount=0;
- unsigned long frequency=0;
- static const unsigned int ArrPwmVal = 16000; //PWM信号周期:1ms, 1KHz
- int pwmvalue=8000; //pwm1value取值范围0~16000;
- float Kp=10,Ki=0.1,Kd=0; //PID参数
- float set_velocity=1000.0, sample_velocity=0;
- float PIDoutvalue=0; //PID运算输出值
- int duty=0; //PWM波占空比
- void Delay1ms(unsigned int c ) //1ms延迟函数
- {
- unsigned int i;
-
- while(c--!=0) //一个while循环占用3个机器周期
- for(i=0;i<3000;i++); //一条for循环占用4个机器周期
- }
- void InitLED(void)
- {
- PD_DDR|=0x60; //设置PD5、PD6为输出模式
- PD_CR1|=0x60; //设置PD5、PD6为推挽输出
- }
- //1KHZ PWM频率;//上桥臂PWM---PC1\PC2\PC3;下桥臂PWM---PB0\PB1\PB2
- void InitTIM1_PWM(void) //16 位高级控制定时器(TIM1);定时器16MHz基准; 只使用了CC1P通道
- {
- //分频,1分频; 计数器的时钟频率(fCK_CNT)等于fCK_PSC/( PSCR[15:0]+1)
- TIM1_PSCRH=0; //预分频器高8位(TIM1_PSCRH)
- TIM1_PSCRL=0; //预分频器低8位(TIM1_PSCRL)
-
- TIM1_ARRH=ArrPwmVal/256;
- TIM1_ARRL=ArrPwmVal%256;
-
- TIM1_CR1 = 0x04; //DIR0:向上计数;URS=1:寄存器被更新时,产生更新中断
- TIM1_CCMR1 = 0x60; //PWM1模式,禁止预装载
-
- TIM1_CCER1=0x01; //CH1通道输出PWM使能,高电平有效
- TIM1_BKR|=0x80; //使能PWM输出 //0x80;使能OC和OCN输出;MOE: 主输出使能
-
-
- TIM1_CR1 |= 0x01; //使能定时计数器
- }
- void TIM2_Init(unsigned int psc,unsigned int arr) //psc 分频系数 arr 计数值
- {
- TIM2_CR1 = 0x00; //向上计数 中断继续计数 关闭计数器
- TIM2_IER = 0x01; //UIE=1:允许更新中断
- TIM2_PSCR = psc; //fMASTER/2^psc;
- TIM2_ARRH = arr/256;
- TIM2_ARRL = arr%256;
- TIM2_CR1 |=0x01; //开始计数
-
- }
- void InitEXTI(void) //PE0作为外中断输入
- { //PEx对应EXTI4_IRQHandler
- EXTI_CR2=0x02; //PE端口下降沿触发中断
- PE_DDR&=0xFE; //PE0为输入模式
- PE_CR1|=0x01; //PE0上拉
- PE_CR2|=0x01; //PE0使能外部中断
- }
- /**************************************************************************
- 函数功能:位置式PID控制器
- 入口参数:编码器测量位置信息,目标位置
- 返回 值:sum
- 根据位置式离散PID公式
- pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)]
- e(k)代表本次偏差
- e(k-1)代表上一次的偏差
- ∑e(k)代表e(k)以及之前的偏差的累积和;
- pwm代表输出
- **************************************************************************/
- float Position_PID (float set_value,float feedback_value)
- {
- static float error,sum,Integral_part,pre_error;
-
- error=set_value-feedback_value; //计算偏差
- Integral_part+=error; //求出偏差的积分
- if(Integral_part>15000) Integral_part=15000;
- if(Integral_part<0) Integral_part=0;
- sum=Kp*error+Ki*Integral_part+Kd*(error-pre_error); //位置式PID控制器
- pre_error=error; //保存上一次偏差
-
- if(sum<0)
- sum=0;
-
- PIDoutvalue=sum;
-
- return sum; //增量输出
- }
- void main( void )
- {
- CLK_CKDIVR=0x00; //HSI不分频,主时钟16M
-
- InitLED();
- InitTIM1_PWM();
- InitEXTI();
-
- asm("sim"); //disable all interrupt EA=0;
- TIM2_Init(8,62499); // 定时器2中断周期: 2^8/16M *62500=1s;
- asm("rim"); //开中断
-
- frequency=0;
-
- while(1)
- {
- sample_velocity=frequency;
- // pwmvalue=(int)Position_PID(set_velocity,sample_velocity);
-
- if(pwmvalue<0)
- pwmvalue=0;
- if(pwmvalue>15900)
- pwmvalue=15900; //PWM限幅
-
-
- TIM1_CCR1H = pwmvalue/256; //PWM1通道占空比寄存器赋值
- TIM1_CCR1L = pwmvalue%256;
-
- duty=pwmvalue/160; //占空比duty=pwmvalue/16000 *100%;
-
- Delay1ms(10); //转速闭环控制周期:10ms;
- }
- }
- #pragma vector=0x09 // 9: EXTI4 端口E外部中断
- __interrupt void EXTI4_IRQHandler(void) //PE
- {
- pulsecount++;
- }
- #pragma vector=15
- __interrupt void TIM2_OVER_INT(void)
- {
- TIM2_SR1 = 0x00;
-
- frequency=pulsecount; //电机旋转1周输出6个脉冲
- pulsecount=0;
-
- PD_ODR ^=0x60; //PD5、PD6闪烁
-
- }
复制代码- //#include "iostm8s103k3.h"
- #include "iostm8s207r8.h"
- //207单片机; 连上仿真器后,ST-LINK-->Option Bytes: AFR5,右键-->Alternate Active,使PB0/PB1/PB2为PWM输出端口功能。
- //16KHZ PWM频率
- //上桥臂PWM---PC1\PC2\PC3
- //下桥臂PWM---PB0\PB1\PB2
- //用杜邦线把PB0与PD5连接起来;先下载程序,再连线;
- //下载运行后,View-->Livewatch,改变pwmvalue1的值,改变PWM1占空比,观察LED1的亮度;
- static const unsigned int ArrPwmVal = 1000; //PWM信号周期; 1000
- unsigned int pwm1value=500;
- void InitTIM1_PWM(void) //16 位高级控制定时器(TIM1);1us定时器时钟基准
- {
- //分频,1分频; 计数器的时钟频率(fCK_CNT)等于fCK_PSC/( PSCR[15:0]+1)
- TIM1_PSCRH=0; //预分频器高8位(TIM1_PSCRH)
- TIM1_PSCRL=15; //预分频器低8位(TIM1_PSCRL)
-
- TIM1_ARRH=ArrPwmVal/256;
- TIM1_ARRL=ArrPwmVal%256;
-
- TIM1_CR1 = 0x04; //DIR0:向上计数;URS=1:寄存器被更新时,产生更新中断
- TIM1_CCMR1 = 0x60; //PWM1模式,禁止预装载
-
- TIM1_CCER1=0x05; //CH1、CH2通道输出PWM使能,高电平有效
- TIM1_BKR|=0x80; //使能PWM输出 //0x80;使能OC和OCN输出;MOE: 主输出使能
- TIM1_DTR=16; //死区62.5ns*16=1us
-
-
- TIM1_CR1 |= 0x01; //使能定时计数器
- }
- void main( void )
- {
-
- CLK_CKDIVR=0x00;//HSI不分频,主时钟16M
- InitTIM1_PWM();
-
- while(1)
- {
- TIM1_CCR1H = pwm1value/256; //PWM1通道占空比10%
- TIM1_CCR1L = pwm1value%256;
-
- }
- }
复制代码
所有资料51hei提供下载:
直流电机伺服控制设计训练.zip
(1.29 MB, 下载次数: 23)
|