标题: 无刷直流电机控制应用——基于STM8S系列单片机 [打印本页]
作者: chy88606 时间: 2017-4-18 20:26
标题: 无刷直流电机控制应用——基于STM8S系列单片机
1、PWM程序
/*摘要:
功能:1. PA4\PA5指示端闪烁,指示系统处于工作状态。
2. 上桥臂开关管PC1\PC2\PC3同时输出占空比40%的PWM信号,即高电平占40%。
3. 下桥臂开关管PB0\PB1\PB2全部处于关断状态,即为低电平。*/
#include "stm8s.h"
#define STM8_FREQ_MHZ 16
#define PWM_FREQUENCY 16000
static const u16 hArrPwmVal = ((u16)((STM8_FREQ_MHZ* (u32)1000000)/PWM_FREQUENCY));
//PWM信号周期
//初始化按键,指示灯端口
void GPIO_int(void)
{
GPIOG->DDR=GPIOG->DDR&0x3f;//PG6,PG7按键配置为输入模式
GPIOG->CR1=GPIOG->CR1|0xC0;//PG6,PG7按键配置为上拉输入
GPIOA->DDR=GPIOA->DDR|0x30;//PA4,PA5指示灯配置为输出模式
GPIOA->CR1=GPIOA->CR1|0x30;//PA4,PA5指示灯d配置为推挽模式
GPIOA->ODR|=0x30;//点亮指示灯
}
//系统时钟配置:内部16M
void Clock_init(void)
{
CLK->CKDIVR=0;
}
//换相电路开关管IO初始化
void PWM_IO_init(void)
{
//PB012 下桥臂1有效
GPIOB->DDR=GPIOB->DDR|0x7;//PB012配置为输出模式
GPIOB->CR1=GPIOB->CR1|0x7;//PB012推挽模式
GPIOB->ODR&=0xf8;//关闭下桥臂开关管
//PC123上桥臂1有效
GPIOC->DDR=GPIOC->DDR|0x0E;//PC123配置为输出模式
GPIOC->CR1=GPIOC->CR1|0x0E;//PC123推挽模式
GPIOC->ODR&=~(0x0E);//关闭上桥臂开关管
}
//高级定时器初始化配置
void Tim1_init(void)
{
//计数器禁止、ARR预装载禁止、边沿对齐模式
TIM1->CR1= 0x04;
TIM1->SMCR= 0;//禁止从模式
TIM1->IER= 0;//禁止所有中断
TIM1->CCER1= 0; //禁止PWM输出
TIM1->CCER2= 0;
TIM1->CCMR1= 0x60; //PWM1模式,禁止预装载
TIM1->CCMR2= 0x60;
TIM1->CCMR3= 0x60;
//prescale= div1 @ 16MHz -> 62.5ns/count, Full scale = 4.09ms
TIM1->PSCRH= 0;
TIM1->PSCRL= 0;
TIM1->ARRH=hArrPwmVal/256;//PWM周期设定
TIM1->ARRL=hArrPwmVal%256;
//disablerepetition counter
TIM1->RCR= 0;
TIM1->CCR1H=0;TIM1->CCR1L=0;//占空比输出均为0
TIM1->CCR2H=0;TIM1->CCR1L=0;
TIM1->CCR3H=0;TIM1->CCR1L=0;
//使能定时计数器
TIM1->CR1|= 0x01;
}
main()
{
unsignedint tem_c=0;
unsignedint outpwm;
for(tem_c=0;tem_c<50000;tem_c++);//上电延时,等待系统稳定
Clock_init();//时钟配置
GPIO_int();//指示灯端口初始化
PWM_IO_init();//开关管控制端口初始化
Tim1_init();//高级定时器配置
outpwm=hArrPwmVal*0.4;//占空比输出设为40%
TIM1->CCR1H= (uint8_t)(outpwm >> 8);
TIM1->CCR1L= (uint8_t)(outpwm);
TIM1->CCR2H= (uint8_t)(outpwm >> 8);
TIM1->CCR2L= (uint8_t)(outpwm);
TIM1->CCR3H= (uint8_t)(outpwm >> 8);
TIM1->CCR3L= (uint8_t)(outpwm);
TIM1->CCER1=0x11;//CH1\CH2通道输出PWM使能,高电平有效
TIM1->CCER2=0x1;//CH3通道输出PWM使能,高电平有效
TIM1->BKR|=TIM1_BKR_MOE;//使能PWM输出
while(1)
{
for(tem_c=0;tem_c<50000;tem_c++);
GPIOA->ODR^=0x30;//PA4\PA5指示灯闪烁
}
}
2、运转程序
(1)hall.h
#include "stm8s.h"
#define H1_PORT GPIOD->IDR
#define H1_PIN BIT4
#define H2_PORT GPIOD->IDR
#define H2_PIN BIT3
#define H3_PORT GPIOD->IDR
#define H3_PIN BIT2
extern unsigned int OutPwmValue;
extern unsigned char bHallStartStep;
#define BIT0 0x01
#define BIT1 0x02
#define BIT2 0x04
#define BIT3 0x08
#define BIT4 0x10
#define BIT5 0x20
#define BIT6 0x40
#define BIT7 0x80
//下桥臂开关控制端口定义
#define MCO0_PORT GPIOB
#define MCO0_PIN GPIO_PIN_0
#define MCO2_PORT GPIOB
#define MCO2_PIN GPIO_PIN_1
#define MCO4_PORT GPIOB
#define MCO4_PIN GPIO_PIN_2
#define PWM_A_ON MCO0_PORT->ODR |= (u8)MCO0_PIN;
#define PWM_B_ON MCO2_PORT->ODR |=(u8)MCO2_PIN;
#define PWM_C_ON MCO4_PORT->ODR |=(u8)MCO4_PIN;
#define PWM_A_OFF MCO0_PORT->ODR &=(u8)(~MCO0_PIN);
#define PWM_B_OFF MCO2_PORT->ODR &=(u8)(~MCO2_PIN);
#define PWM_C_OFF MCO2_PORT->ODR &= (u8)(~MCO4_PIN);
void Init_TIM2(void);
void TIM2_InitCapturePolarity(void);
void ComHandler(void);
(2)hall.c
#include "hall.h"
unsigned char bHallStartStep;//换相步序变量定义
//换相步序值0-5分别对应AB\AC\BC\BA\CA\CB
unsigned int OutPwmValue=0;//PWM输出值变量定义
unsigned char bHallSteps[2][8]={
{7,5,3,4,1,0,2,7},//正转
{7,2,0,1,4,3,5,7}//反转
};
const unsigned charPWM_EN1_TAB[6]={0x01,0x01,0x10,0x10,0x00,0x00};
//六步法中,CH1\CH2通道极性及使能配置
const unsigned charPWM_EN2_TAB[6]={0x0,0x00,0x00,0x0,0x1,0x1};
//六步法中,CH3通道极性及使能配置
//初始化HALL捕获输入定义器
void Init_TIM2(void)
{
//计数器禁止、ARR预装载禁止、向上计数、边沿对齐模式
TIM2->CR1= BIT2;
//禁止TIM2所有中断
TIM2->IER= 0;//禁止中断
TIM2->CCMR1= 0x01;//TIM2的CH1\CH2\CH3通道配置为输入
TIM2->CCMR2= 0x01;
TIM2->CCMR3= 0x01;
#defineIC_FILTER (u8)(5 << 4)
TIM2->CCMR1|= IC_FILTER; //输入捕获滤波器
TIM2->CCMR2|= IC_FILTER;
TIM2->CCMR3|= IC_FILTER;
//prescale= div3 @ 16MHz -> 0.5us/count * 24MHz -> 0.33us/count
TIM2->PSCR= 0;
TIM2->ARRH=0xff;//计数周期设为最大
TIM2->ARRL=0xff;
TIM2->CCER1|= 0x01;//TIM2的CH1\CH2\CH3通道使能捕获功能
TIM2->CCER1|= 0x10;
TIM2->CCER2|= 0x01;
TIM2->CR1|= 0x01;//使能TIM2定时器
}
//根据HALL状态换相,启动电机运行
void TIM2_InitCapturePolarity(void)
{
u8bHStatus = 0;
GPIOD->DDR&= (u8)(~(0x1c));//HALL端口模式配置
//Read status of H1 and set the expected polarity
if(H1_PORT & H1_PIN)
{
TIM2->CCER1|= BIT1;
bHStatus|= BIT2;
}
else
{
TIM2->CCER1&= (u8)(~(BIT1));
}
//Read status of H2 and set the expected polarity
if(H2_PORT & H2_PIN)
{
TIM2->CCER1|= BIT5;
bHStatus|= BIT1;
}
else
{
TIM2->CCER1&= (u8)(~(BIT5));
}
//Read status of H3 and set the expected polarity
if(H3_PORT & H3_PIN)
{
TIM2->CCER2|= BIT1;
bHStatus|= BIT0;
}
else
{
TIM2->CCER2&= (u8)(~(BIT1));
}
bHallStartStep= bHallSteps[0][bHStatus];//得到换相步序
if(bHallStartStep == 7)//不该出现的HALL状态
{
return;
}
TIM2->SR1=(u8)~(TIM2_IT_CC3|TIM2_IT_CC2|TIM2_IT_CC1);
TIM2->IER= 0x0e;//使能输入捕获中断
ComHandler();//输出PWM信号,启动电机
}
//捕获中断,即HALL状态变化时,进入此中断
@near @interrupt @svlreg voidTIM2_CAP_COM_IRQHandler(void)
{
u8bHStatus = 0;
//Read status of H1 and set the expected polarity
if(H1_PORT & H1_PIN)
{
TIM2->CCER1|= BIT1;
bHStatus|= BIT2;
}
else
{
TIM2->CCER1&= (u8)(~(BIT1));
}
//Read status of H2 and set the expected polarity
if(H2_PORT & H2_PIN)
{
TIM2->CCER1|= BIT5;
bHStatus|= BIT1;
}
else
{
TIM2->CCER1&= (u8)(~(BIT5));
}
//Read status of H3 and set the expected polarity
if(H3_PORT & H3_PIN)
{
TIM2->CCER2|= BIT1;
bHStatus|= BIT0;
}
else
{
TIM2->CCER2&= (u8)(~(BIT1));
}
if(TIM2->SR1 & BIT2)
{
TIM2->SR1=(u8)(~TIM2_IT_CC2);
}
if(TIM2->SR1 & BIT1)
{
TIM2->SR1=(u8)(~TIM2_IT_CC1);
}
if(TIM2->SR1 & BIT3)
{
TIM2->SR1=(u8)(~TIM2_IT_CC3);
}
bHallStartStep= bHallSteps[0][bHStatus];//得到换相步序
if(bHallStartStep == 7)
{ //故障,停止输出
TIM1->BKR&= (uint8_t)(~TIM1_BKR_MOE);//禁止PWM输出
PWM_A_OFF;
PWM_B_OFF;
PWM_C_OFF;
return;
}
ComHandler(); //换相
return;
}
//换相子函数
void ComHandler(void)
{
TIM1->BKR&= (uint8_t)(~TIM1_BKR_MOE);//禁止PWM输出
if(bHallStartStep!=3&&bHallStartStep!=4)
PWM_A_OFF;
if(bHallStartStep!=0&&bHallStartStep!=5)
PWM_B_OFF;
if(bHallStartStep!=1&&bHallStartStep!=2)
PWM_C_OFF;
//根据换相步序,打开不同的开关管,并施加正确的PWM信号
if(bHallStartStep==0)//AB
{
TIM1->CCR1H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR1L = (uint8_t)(OutPwmValue);
PWM_B_ON;
}
elseif(bHallStartStep==1) //AC
{
TIM1->CCR1H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR1L = (uint8_t)(OutPwmValue);
PWM_C_ON;
}
elseif(bHallStartStep==2) //BC
{
TIM1->CCR2H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR2L = (uint8_t)(OutPwmValue);
PWM_C_ON;
}
elseif(bHallStartStep==3) //BA
{
TIM1->CCR2H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR2L = (uint8_t)(OutPwmValue);
PWM_A_ON;
}
elseif(bHallStartStep==4)//CA
{
TIM1->CCR3H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR3L = (uint8_t)(OutPwmValue);
PWM_A_ON;
}
elseif(bHallStartStep==5) //CB
{
TIM1->CCR3H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR3L = (uint8_t)(OutPwmValue);
PWM_B_ON;
}
TIM1->CCER1=PWM_EN1_TAB[bHallStartStep];
TIM1->CCER2=PWM_EN2_TAB[bHallStartStep];
TIM1->BKR|=TIM1_BKR_MOE;//使能PWM输出
}
(3)mian.c
/*摘要:
功能:1. PA4\PA5指示端闪烁,指示系统处于工作状态。
2. 上桥臂开关管PC1\PC2\PC3输出占空比20%的PWM信号,即高电平占20%。
3. 上电根据HALL状态换相,并在输出PWM信号后,电机会转动,同时HALL信号不断改变,然后进入捕获中断,进行及时换相。如此实现电机的运转控制。*/
#include "stm8s.h"
#include "hall.h"
#define STM8_FREQ_MHZ 16
#define PWM_FREQUENCY 16000
static const u16 hArrPwmVal =((u16)((STM8_FREQ_MHZ * (u32)1000000)/PWM_FREQUENCY));
//PWM信号周期
//初始化按键,指示灯端口
void GPIO_int(void)
{
GPIOG->DDR=GPIOG->DDR&0x3f;//PG6,PG7按键配置为输入模式
GPIOG->CR1=GPIOG->CR1|0xC0;//PG6,PG7按键配置为上拉输入
GPIOA->DDR=GPIOA->DDR|0x30;//PA4,PA5指示灯配置为输出模式
GPIOA->CR1=GPIOA->CR1|0x30;//PA4,PA5指示灯d配置为推挽模式
GPIOA->ODR|=0x30;//点亮指示灯
}
//系统时钟配置:内部16M
void Clock_init(void)
{
CLK->CKDIVR=0;
}
//换相电路开关管IO初始化
void PWM_IO_init(void)
{
//PB012 下桥臂1有效
GPIOB->DDR=GPIOB->DDR|0x7;//PB012配置为输出模式
GPIOB->CR1=GPIOB->CR1|0x7;//PB012推挽模式
GPIOB->ODR&=0xf8;//关闭下桥臂开关管
//PC123上桥臂1有效
GPIOC->DDR=GPIOC->DDR|0x0E;//PC123配置为输出模式
GPIOC->CR1=GPIOC->CR1|0x0E;//PC123推挽模式
GPIOC->ODR&=~(0x0E);//关闭上桥臂开关管
}
//高级定时器初始化配置
void Tim1_init(void)
{
//计数器禁止、ARR预装载禁止、边沿对齐模式
TIM1->CR1= 0x04;
TIM1->SMCR= 0;//禁止从模式
TIM1->IER= 0;//禁止所有中断
TIM1->CCER1= 0; //禁止PWM输出
TIM1->CCER2= 0;
TIM1->CCMR1= 0x60; //PWM1模式,禁止预装载
TIM1->CCMR2= 0x60;
TIM1->CCMR3= 0x60;
//prescale= div1 @ 16MHz -> 62.5ns/count, Full scale = 4.09ms
TIM1->PSCRH= 0;
TIM1->PSCRL= 0;
TIM1->ARRH=hArrPwmVal/256;//PWM周期设定
TIM1->ARRL=hArrPwmVal%256;
//disablerepetition counter
TIM1->RCR= 0;
TIM1->CCR1H=0;TIM1->CCR1L=0;//占空比输出均为0
TIM1->CCR2H=0;TIM1->CCR1L=0;
TIM1->CCR3H=0;TIM1->CCR1L=0;
//使能定时计数器
TIM1->CR1|= 0x01;
}
main()
{
unsignedint tem_c=0;
for(tem_c=0;tem_c<50000;tem_c++);//上电延时,等待系统稳定
Clock_init();//时钟配置
GPIO_int();//指示灯端口初始化
PWM_IO_init();//开关管控制端口初始化
Tim1_init();//高级定时器配置
Init_TIM2();//捕获输入定时器初始化配置
enableInterrupts();
OutPwmValue=hArrPwmVal*0.2;//固定20%占空比的PWM值
TIM2_InitCapturePolarity();//根据HALL状态输出PWM状态,启动电机运行
while(1)
{
for(tem_c=0;tem_c<50000;tem_c++);
GPIOA->ODR^=0x30;//PA4\PA5指示灯闪烁
}
}
3、启停和调速
(1)hall.h
#include "stm8s.h"
#define H1_PORT GPIOD->IDR
#define H1_PIN BIT4
#define H2_PORT GPIOD->IDR
#define H2_PIN BIT3
#define H3_PORT GPIOD->IDR
#define H3_PIN BIT2
extern unsigned char St_F;//启停变量
extern unsigned char FaultF;//故障标志
extern unsigned char Run_dir;//运转标志
extern unsigned int OutPwmValue;
extern unsigned char bHallStartStep;
#define BIT0 0x01
#define BIT1 0x02
#define BIT2 0x04
#define BIT3 0x08
#define BIT4 0x10
#define BIT5 0x20
#define BIT6 0x40
#define BIT7 0x80
//下桥臂开关控制端口定义
#define MCO0_PORT GPIOB
#define MCO0_PIN GPIO_PIN_0
#define MCO2_PORT GPIOB
#define MCO2_PIN GPIO_PIN_1
#define MCO4_PORT GPIOB
#define MCO4_PIN GPIO_PIN_2
#define PWM_A_ON MCO0_PORT->ODR |=(u8)MCO0_PIN;
#define PWM_B_ON MCO2_PORT->ODR |=(u8)MCO2_PIN;
#define PWM_C_ON MCO4_PORT->ODR |=(u8)MCO4_PIN;
#define PWM_A_OFF MCO0_PORT->ODR &=(u8)(~MCO0_PIN);
#define PWM_B_OFF MCO2_PORT->ODR &=(u8)(~MCO2_PIN);
#define PWM_C_OFF MCO2_PORT->ODR &=(u8)(~MCO4_PIN);
void Init_TIM2(void);
void TIM2_InitCapturePolarity(void);
void ComHandler(void);
(2)hall.c
#include "hall.h"
unsigned char bHallStartStep;//换相步序变量定义
//换相步序值0-5分别对应AB\AC\BC\BA\CA\CB
unsigned int OutPwmValue=0;//PWM输出值变量定义
unsigned char St_F=0;//启停标志,0时为停止,1时为启动
unsigned char FaultF=0;//故障标志
unsigned char Run_dir=0;//运转方向,0-1对立
unsigned char bHallSteps[2][8]={
{7,5,3,4,1,0,2,7},//正转
{7,2,0,1,4,3,5,7}//反转
};
const unsigned charPWM_EN1_TAB[6]={0x01,0x01,0x10,0x10,0x00,0x00};
//六步法中,CH1\CH2通道极性及使能配置
const unsigned charPWM_EN2_TAB[6]={0x0,0x00,0x00,0x0,0x1,0x1};
//六步法中,CH3通道极性及使能配置
//初始化HALL捕获输入定义器
void Init_TIM2(void)
{
//计数器禁止、ARR预装载禁止、向上计数、边沿对齐模式
TIM2->CR1= BIT2;
//禁止TIM2所有中断
TIM2->IER= 0;//禁止中断
TIM2->CCMR1= 0x01;//TIM2的CH1\CH2\CH3通道配置为输入
TIM2->CCMR2= 0x01;
TIM2->CCMR3= 0x01;
#defineIC_FILTER (u8)(5 << 4)
TIM2->CCMR1|= IC_FILTER; //输入捕获滤波器
TIM2->CCMR2|= IC_FILTER;
TIM2->CCMR3|= IC_FILTER;
//prescale= div3 @ 16MHz -> 0.5us/count * 24MHz -> 0.33us/count
TIM2->PSCR= 0;
TIM2->ARRH=0xff;//计数周期设为最大
TIM2->ARRL=0xff;
TIM2->CCER1|= 0x01;//TIM2的CH1\CH2\CH3通道使能捕获功能
TIM2->CCER1|= 0x10;
TIM2->CCER2|= 0x01;
TIM2->CR1|= 0x01;//使能TIM2定时器
}
//根据HALL状态换相,启动电机运行
void TIM2_InitCapturePolarity(void)
{
u8bHStatus = 0;
GPIOD->DDR&= (u8)(~(0x1c));//HALL端口模式配置
//Read status of H1 and set the expected polarity
if(H1_PORT & H1_PIN)
{
TIM2->CCER1|= BIT1;
bHStatus|= BIT2;
}
else
{
TIM2->CCER1&= (u8)(~(BIT1));
}
//Read status of H2 and set the expected polarity
if(H2_PORT & H2_PIN)
{
TIM2->CCER1|= BIT5;
bHStatus|= BIT1;
}
else
{
TIM2->CCER1&= (u8)(~(BIT5));
}
//Read status of H3 and set the expected polarity
if(H3_PORT & H3_PIN)
{
TIM2->CCER2|= BIT1;
bHStatus|= BIT0;
}
else
{
TIM2->CCER2&= (u8)(~(BIT1));
}
bHallStartStep= bHallSteps[Run_dir][bHStatus];//得到换相步序
if(bHallStartStep == 7)//不该出现的HALL状态
{
return;
}
TIM2->SR1=(u8)~(TIM2_IT_CC3|TIM2_IT_CC2|TIM2_IT_CC1);
TIM2->IER= 0x0e;//使能输入捕获中断
ComHandler();//输出PWM信号,启动电机
}
//捕获中断,即HALL状态变化时,进入此中断
@near @interrupt @svlreg voidTIM2_CAP_COM_IRQHandler(void)
{
u8bHStatus = 0;
//Read status of H1 and set the expected polarity
if(H1_PORT & H1_PIN)
{
TIM2->CCER1|= BIT1;
bHStatus|= BIT2;
}
else
{
TIM2->CCER1&= (u8)(~(BIT1));
}
//Read status of H2 and set the expected polarity
if(H2_PORT & H2_PIN)
{
TIM2->CCER1|= BIT5;
bHStatus|= BIT1;
}
else
{
TIM2->CCER1&= (u8)(~(BIT5));
}
//Read status of H3 and set the expected polarity
if(H3_PORT & H3_PIN)
{
TIM2->CCER2|= BIT1;
bHStatus|= BIT0;
}
else
{
TIM2->CCER2&= (u8)(~(BIT1));
}
if(TIM2->SR1 & BIT2)
{
TIM2->SR1=(u8)(~TIM2_IT_CC2);
}
if(TIM2->SR1 & BIT1)
{
TIM2->SR1=(u8)(~TIM2_IT_CC1);
}
if(TIM2->SR1 & BIT3)
{
TIM2->SR1=(u8)(~TIM2_IT_CC3);
}
bHallStartStep= bHallSteps[Run_dir][bHStatus];//得到换相步序
if(bHallStartStep == 7)
{ //故障,停止输出
TIM1->BKR&= (uint8_t)(~TIM1_BKR_MOE);//禁止PWM输出
PWM_A_OFF;
PWM_B_OFF;
PWM_C_OFF;
return;
}
ComHandler(); //换相
return;
}
//换相子函数
void ComHandler(void)
{
TIM1->BKR&= (uint8_t)(~TIM1_BKR_MOE);//禁止PWM输出
if(FaultF!=0||St_F==0)
{PWM_A_OFF;PWM_B_OFF;PWM_C_OFF;return;}
if(bHallStartStep!=3&&bHallStartStep!=4)
PWM_A_OFF;
if(bHallStartStep!=0&&bHallStartStep!=5)
PWM_B_OFF;
if(bHallStartStep!=1&&bHallStartStep!=2)
PWM_C_OFF;
//根据换相步序,打开不同的开关管,并施加正确的PWM信号
if(bHallStartStep==0)//AB
{
TIM1->CCR1H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR1L = (uint8_t)(OutPwmValue);
PWM_B_ON;
}
elseif(bHallStartStep==1) //AC
{
TIM1->CCR1H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR1L = (uint8_t)(OutPwmValue);
PWM_C_ON;
}
elseif(bHallStartStep==2) //BC
{
TIM1->CCR2H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR2L = (uint8_t)(OutPwmValue);
PWM_C_ON;
}
elseif(bHallStartStep==3) //BA
{
TIM1->CCR2H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR2L = (uint8_t)(OutPwmValue);
PWM_A_ON;
}
elseif(bHallStartStep==4)//CA
{
TIM1->CCR3H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR3L = (uint8_t)(OutPwmValue);
PWM_A_ON;
}
elseif(bHallStartStep==5) //CB
{
TIM1->CCR3H= (uint8_t)(OutPwmValue >> 8);
TIM1->CCR3L = (uint8_t)(OutPwmValue);
PWM_B_ON;
}
TIM1->CCER1=PWM_EN1_TAB[bHallStartStep];
TIM1->CCER2=PWM_EN2_TAB[bHallStartStep];
TIM1->BKR|=TIM1_BKR_MOE;//使能PWM输出
}
(3)mian.c
/*功能:
1. PD5指示灯,上电亮,指示系统处于工作状态。
2.PA4指示灯,指示电机启停与否。
3.PA5指示灯,指示电机运行方向
4.上桥臂开关管PC1\PC2\PC3输出可变PWM信号,以完成调速功能。
5.PG7按键为电机启停控制键,PG6为电机方向切换键。
6.PF5电位器,旋转时实现PWM开环调速功能。*/
#include "stm8s.h"
#include "hall.h"
#define STM8_FREQ_MHZ 16
#define PWM_FREQUENCY 16000
static const u16 hArrPwmVal =((u16)((STM8_FREQ_MHZ * (u32)1000000)/PWM_FREQUENCY));
//PWM信号周期
//hArrPwmVal=1000
#define MINPWMPERCENT 10
#define MAXPWMPERCENT 90
#define MINVALUE MINPWMPERCENT*10
//hArrPwmVal=1000
//MINPWMPERCENT*hArrPwmVal/100简化为MINPWMPERCENT*10
#define MAXVALUE MAXPWMPERCENT*10
//MAXPWMPERCENT*hArrPwmVal/100简化MAXPWMPERCENT*10
//初始化按键,指示灯端口
void GPIO_int(void)
{
GPIOG->DDR=GPIOG->DDR&0x3f;//PG6,PG7按键配置为输入模式
GPIOG->CR1=GPIOG->CR1|0xC0;//PG6,PG7按键配置为上拉输入
GPIOA->DDR=GPIOA->DDR|0x30;//PA4,PA5指示灯配置为输出模式
GPIOA->CR1=GPIOA->CR1|0x30;//PA4,PA5指示灯d配置为推挽模式
GPIOA->ODR|=0x30;//关闭指示灯
GPIOD->DDR=GPIOD->DDR|0x20;//PD5指示灯配置为输出模式
GPIOD->CR1=GPIOD->CR1|0x20;//PD5指示灯d配置为推挽模式
GPIOD->ODR&=~0x20;//点亮指示灯,指示系统工作
}
//系统时钟配置:内部16M
void Clock_init(void)
{
CLK->CKDIVR=0;
}
//电位器调速AD初始 PF5 初始化 AIN13
void AD_int(void)
{
u8value;
u16ADC_TDR_tmp;
ADC2->CSR= 13; //AIN13通道选择
//select4MHz clock based on 16MHz fMaster (div4), single mode
ADC2->CR1= 0x20;
ADC2->CR2= 0x08;//数据右对齐
ADC2->TDRH=0x20;//AIN13禁止施密特触发
ADC2->CR1|= 0X01;//使能ADC
value=30;
while(value--);//等待ADC稳定
ADC2->CSR&= 0x7f;//清EOC标志
ADC2->CR1|= 0x01;//启动AD
}
//换相电路开关管IO初始化
void PWM_IO_init(void)
{
//PB012 下桥臂1有效
GPIOB->DDR=GPIOB->DDR|0x7;//PB012配置为输出模式
GPIOB->CR1=GPIOB->CR1|0x7;//PB012推挽模式
GPIOB->ODR&=0xf8;//关闭下桥臂开关管
//PC123上桥臂1有效
GPIOC->DDR=GPIOC->DDR|0x0E;//PC123配置为输出模式
GPIOC->CR1=GPIOC->CR1|0x0E;//PC123推挽模式
GPIOC->ODR&=~(0x0E);//关闭上桥臂开关管
}
//高级定时器初始化配置
void Tim1_init(void)
{
//计数器禁止、ARR预装载禁止、边沿对齐模式
TIM1->CR1= 0x04;
TIM1->SMCR= 0;//禁止从模式
TIM1->IER= 0;//禁止所有中断
TIM1->CCER1= 0; //禁止PWM输出
TIM1->CCER2= 0;
TIM1->CCMR1= 0x60; //PWM1模式,禁止预装载
TIM1->CCMR2= 0x60;
TIM1->CCMR3= 0x60;
//prescale= div1 @ 16MHz -> 62.5ns/count, Full scale = 4.09ms
TIM1->PSCRH= 0;
TIM1->PSCRL= 0;
TIM1->ARRH=hArrPwmVal/256;//PWM周期设定
TIM1->ARRL=hArrPwmVal%256;
//disablerepetition counter
TIM1->RCR= 0;
TIM1->CCR1H=0;TIM1->CCR1L=0;//占空比输出均为0
TIM1->CCR2H=0;TIM1->CCR1L=0;
TIM1->CCR3H=0;TIM1->CCR1L=0;
//使能定时计数器
TIM1->CR1|= 0x01;
}
main()
{
unsignedint tem_c=0;
unsignedchar B_k1=0,B_k2=0;
unsignedint ADConverValue=0;
for(tem_c=0;tem_c<50000;tem_c++);//上电延时,等待系统稳定
Clock_init();//时钟配置
GPIO_int();//指示灯端口初始化
PWM_IO_init();//开关管控制端口初始化
Tim1_init();//高级定时器配置
Init_TIM2();//捕获输入定时器初始化配置
enableInterrupts();
AD_int();
OutPwmValue=MINVALUE;
while(1)
{if((GPIOG->IDR&0x80)==0x80)B_k1=0;//PG7为启停键
elseif(B_k1==0)//PG7按下时,指示灯亮
{
for(tem_c=0;tem_c<500;tem_c++);
if((GPIOG->IDR&0x80)==0x00)
{
B_k1=1;
if(FaultF!=0)FaultF=0;//当前处于故障状态
St_F=1-St_F;//启停标志变量改变
if(St_F==1)//启动
{
TIM2_InitCapturePolarity();
//根据HALL状态输出PWM状态,启动电机运行
GPIOA->ODR&=~(0x10);
//PA4指示灯亮,表示启动电机
}
else
{
ComHandler();//根据启停标志变量关闭PWM输出。
GPIOA->ODR|=0x10;//电机停止运行指示灯指示
}
}
}
if((GPIOG->IDR&0x40)==0x40)B_k2=0;//PG6为方向键
elseif(B_k2==0)//PG7按下时,指示灯灭
{
for(tem_c=0;tem_c<500;tem_c++);
if((GPIOG->IDR&0x40)==0x00)
{
B_k2=1;
if(St_F==0)//电机处于停止状态
{
Run_dir=1-Run_dir;//方向切换
GPIOA->ODR^=0x20;//PA5指示灯变换
}
}
}
if(ADC2->CSR&0x80)
{
ADC2->CSR&= (u8)(~0x80);//清除EOC标志
ADConverValue=ADC2->DRH*256+ADC2->DRL;//读取AD转换值
ADC2->CR1|= 0x01;//启动AD
if(ADConverValue<MINVALUE) ADConverValue=MINVALUE;
elseif(ADConverValue>MAXVALUE) ADConverValue=MAXVALUE;
OutPwmValue=ADConverValue;//赋值PWM输出变量值
}
if(FaultF==1)
{
ComHandler();//故障时,关闭PWM输出
FaultF=2;
}
}
}
作者: chy88606 时间: 2017-4-18 20:27
这是一本书的源代码 李家庆 李芳 叶问的
作者: @老表 时间: 2017-4-19 14:56
我想问51单片机能不能直接控制步进电机或者直流电机,我想制作一个单片机传感器、控制电机正反转’
作者: chy88606 时间: 2017-5-8 10:06
单片机完全可以控制步进电机和直流电机 没问题的
作者: chy88606 时间: 2017-5-8 10:07
可以的 51控制步进电机和直流电机完全没问题
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |