标题:
PIC单片机PWM电机速度控制源码-实用C语言程序设计与典型实例
[打印本页]
作者:
likanghei
时间:
2018-5-19 11:27
标题:
PIC单片机PWM电机速度控制源码-实用C语言程序设计与典型实例
与PIC单片机实用C语言程序设计与典型实例书籍配套的光盘实例,包括原理图和C语言程序文件,希望对大家有所帮助!
0.jpg
(90.54 KB, 下载次数: 134)
下载附件
2018-5-20 02:38 上传
单片机源程序如下:
#include <p18cxxx.h>
#include "16x2LCDDriver.h"
unsigned char LCDBuffer_0[]={"STOP 00% DIR +"};
unsigned char LCDBuffer_1[]={"Get Spd 0000 RPM"};
struct TMR1COUNTER_STRUCT
{
unsigned char HighCounter;
unsigned int LowCounter;
unsigned char ChangeFlag;
};
struct TMR1COUNTER_STRUCT MyTMR1,MyTMR3,GetTMR1,GetTMR3;
void OSCillator_Initize(void)
{
OSCCON=0x70;//选择内部8MHz的主振荡器
OSCTUNE=0x40;//使能4xPLL--->Fosc=32MHz
}
void PIC_PortDir_Initize(void)
{
ADCON1=0x0F;//RA和RE端口全为数字IO口
TRISD=0x00;//RD端口置输出方向
TRISE=0x00;//RE端口置输出方向
TRISCbits.TRISC1=0;
TRISCbits.TRISC2=0;
TRISCbits.TRISC3=0;
}
void PIC_TMR0_Initize(void)
{
T0CONbits.TMR0ON=0;//TMR0停止工作
T0CONbits.T08BIT=0;//选择16位的定时/计数器
T0CONbits.T0CS=0;//选择内部CLKO时钟源作为定时
T0CONbits.PSA=0;//选择预分频器
T0CONbits.T0PS2=1;//预分频比为1:256
T0CONbits.T0PS1=1;
T0CONbits.T0PS0=1;
TMR0H=(65536-31250)/256;//先写高字节
TMR0L=(65536-31250)%256;//再写低字节
T0CONbits.TMR0ON=1;//开始定时工作
}
void PIC_TMR1_Initize(void)
{
//此处TMR1的预分频比为1:1
T1CONbits.RD16=1;//允许一次性读写16位
T1CONbits.TMR1CS=1;//选择外部时钟源,TMR1用作外部计数
TMR1H=0;//TMR1数据寄存器清0
TMR1L=0;
T1CONbits.TMR1ON=1;//允许TMR1开始工作
}
void PIC_TMR3_Initize(void)
{
//此处TMR1的预分频比为1:8
T3CONbits.T3CKPS1=1;
T3CONbits.T3CKPS0=1;
T3CONbits.RD16=1;//允许一次性读写16位
T3CONbits.TMR3CS=0;//选择内部时钟源,TMR3用作内部计数
TMR3H=0;//TMR3数据寄存器清0
TMR3L=0;
T3CONbits.TMR3ON=1;//允许TMR3开始工作
}
void PIC_Interrupt_Initize(void)
{
INTCONbits.TMR0IF=0;//TMR0溢出标志位清0
INTCONbits.TMR0IE=1;//TMR0溢出中断允许
PIR1bits.TMR1IF=0;//TMR1溢出标志位清0
PIE1bits.TMR1IE=1;//TMR1溢出中断允许
IPR1bits.TMR1IP=0;//低优先级
PIR2bits.TMR3IF=0;//TMR1溢出标志位清0
PIE2bits.TMR3IE=1;//TMR1溢出中断允许
IPR2bits.TMR3IP=0;//低优先级
INTCONbits.INT0IF=0;//清INT0中断标志位
//INTCONbits.INT0IE=1;//INT0中断允许
INTCON2bits.RBPU=0;//允许内部弱上拉
INTCON2bits.INTEDG0=1;//上边沿触发中断
RCONbits.IPEN=1;//允许中断优先级位
INTCONbits.GIE=1;//CPU全局中断使能允许
INTCONbits.PEIE=1;//CPU第二梯队中断使能允许
}
void PIC_CCPForPWM_Initize(void)
{
TRISCbits.TRISC1=0;//RC1置输出方向
TRISCbits.TRISC2=0;//RC2置输出方向
LATCbits.LATC1=0;//RC1引脚输出为0
LATCbits.LATC2=0;//RC2引脚输出为0
CCP1CON=0x0F;//CCP1设置为PWM模式
CCP2CON=0x0F;//CCP2设置为PWM模式
T2CON=0x03;//TMR2的预分频为1:16
T2CONbits.TMR2ON=1;//TMR2开始工作
PR2=249;//PWM周期为2000Hz,FOSC=32MHz
CCPR1L=0;//PWM1的占空比为0
CCPR2L=0;//PWM2的占空比为0
}
unsigned char CycleFlag;
unsigned char FreqFlag;
#define RUNSTOPKEY PORTBbits.RB3
#define PWMKEY PORTBbits.RB4
#define DIRKEY PORTBbits.RB5
unsigned char MotorRunStatus;
unsigned char MotorDirection;
unsigned char MotorPWMData;
unsigned char RunStopKeyFlag;
unsigned int RunStopKeyCounter;
unsigned char DirKeyFlag;
unsigned int DirKeyCounter;
unsigned char PWMKeyFlag;
unsigned int PWMKeyCounter;
void SystemVariant_Initize(void)
{
MotorPWMData=0;
}
void Motor_Control(unsigned char Direction,
unsigned char Speed)
{
switch(Direction)
{
case 0:
CCPR1L=0;
CCPR2L=0;
CCPR1L=Speed;
break;
case 1:
CCPR2L=0;
CCPR1L=0;
CCPR2L=Speed;
break;
}
}
//-------------------------------------------------------------------
void PIC18F_High_isr(void);//高优先级中断函数声明
#pragma code high_vector_section=0x8
void high_vector (void)
{
_asm goto PIC18F_High_isr _endasm
}
void SystemInterruptISR(void);//低优先级中断函数声明
#pragma code low_vector=0x18//低中断优先级
void low_interrupt(void)
{
_asm goto SystemInterruptISR _endasm
}
#pragma code
//-------------------------------------------------------------------
void main(void)
{
unsigned long temp;
unsigned char i;
OSCillator_Initize();//CPU系统时钟初始化内部时钟源8MHz,经过4xPLL
PIC_PortDir_Initize();//PIC单片机的使用到的I/O口方向初始化
PIC_TMR0_Initize();//PIC单片机的TMR0定时器初始化为内部定时方式
PIC_TMR1_Initize();//PIC单片机的TMR1定时器初始化为外部计数方式
PIC_TMR3_Initize();
PIC_CCPForPWM_Initize();
PIC_Interrupt_Initize();
initize_lcd();
while(1)
{
if(0==RUNSTOPKEY)//判断启动按键是否按下
{
if(0==RunStopKeyFlag)//检测启动按键是否成功按下标志
{
RunStopKeyCounter++;//软件计数器,用于按键去抖动
if(4000==RunStopKeyCounter)//按键去抖动延时到
{
RunStopKeyCounter=0;//清软计数器为0
if(0==RUNSTOPKEY)//再判断启动按键是否真得按下
{
RunStopKeyFlag=1;//置启动按键成功按下标志为1
if(0==MotorRunStatus)//如果电机是处理停止状态
{//则启动电机运转
MotorRunStatus=1;//同时置电机状态为1
LCDBuffer_0[0]='R';//LCD显示屏上显示"RUN"
LCDBuffer_0[1]='U';
LCDBuffer_0[2]='N';
LCDBuffer_0[3]=' ';
LCDBuffer_0[4]=' ';
temp=MotorPWMData;//读取设置电机速度的变量
temp<<=1;//转换成占空比送到LCD上显示
temp/=5;
LCDBuffer_0[5]=(temp/10)+0x30;
LCDBuffer_0[6]=(temp%10)+0x30;
LCDBuffer_0[7]='%';
LCDBuffer_0[8]=' ';
LCDBuffer_0[9]='D';
LCDBuffer_0[10]='I';
LCDBuffer_0[11]='R';
LCDBuffer_0[12]=' ';
if(0==MotorDirection)//根据电机运转的方向
{//来设置电机是正转还是反转,并在LCD上显示
CCPR1L=0;
CCPR2L=0;
CCPR1L=MotorPWMData;//使RC1引脚输出PWM信号
LCDBuffer_0[13]='+';//表示电机正转
}
else
{
CCPR2L=0;
CCPR1L=0;
CCPR2L=MotorPWMData;//使RC2引脚输出PWM信号
LCDBuffer_0[13]='-';//表示电机反转
}
}
else//如果电机是在运转中,则这时按下该键可以停止电机运转
{
MotorRunStatus=0;//置电机运动状态为0
LCDBuffer_0[0]='S';//LCD屏上显示"STOP"
LCDBuffer_0[1]='T';
LCDBuffer_0[2]='O';
LCDBuffer_0[3]='P';
LCDBuffer_0[4]=' ';
LCDBuffer_0[5]='0';
LCDBuffer_0[6]='0';
CCPR1L=0;//RC1和RC2引脚不输出PWM信号
CCPR2L=0;
}
lcd_displaystr(0,0,LCDBuffer_0);//将字符串送到LCD上显示
}
}
}
}
else
{
if(1==RUNSTOPKEY)//等待按键释放处理过程
{
if(1==RunStopKeyFlag)
{
RunStopKeyFlag=0;//清启动按键上次成功按下标志
RunStopKeyCounter=0;//消抖动延时计数器清0
}
}
}
if(0==DIRKEY)//判断电机运转方向切换键是否按下
{
if(0==DirKeyFlag)//判断方向切换键的标志是否成功
{
DirKeyCounter++;//去抖动计数器加1
if(4000==DirKeyCounter)//去抖动延时时间到
{
DirKeyCounter=0;//计数器清0
if(0==DIRKEY)//判断是否真得按下
{
DirKeyFlag=1;//置成功按下标志成立
if(0==MotorDirection)//电机是正转方向吗?
{
MotorDirection=1;//置反向运转方向状态
LCDBuffer_0[13]='-';//LCD显示屏显示"-"
CCPR2L=0;
CCPR1L=0;
CCPR2L=MotorPWMData;//启动RC2输出PWM信号
}
else
{
MotorDirection=0;//置正向运转方向状态
LCDBuffer_0[13]='+';//LCD显示屏上显示"+"
CCPR1L=0;
CCPR2L=0;
CCPR1L=MotorPWMData;//启运RC1输出PWM信号
}
lcd_displaystr(0,0,LCDBuffer_0);//将字符串送到LCD上显示
}
}
}
}
else
{
if(1==DIRKEY)//等待按键释放
{
if(1==DirKeyFlag)//如果上次按键按下标志成功,则
{
DirKeyFlag=0;//清按键按下标志
DirKeyCounter=0;//清计数器为0
}
}
}
if(0==PWMKEY)//判断电机速度调节键是否按下
{
if(0==PWMKeyFlag)//判断按键按下标志是否为0
{
PWMKeyCounter++;//去抖动计数器加1
if(4000==PWMKeyCounter)//支抖动延时时间到
{
PWMKeyCounter=0;//清计数器为0
if(0==PWMKEY)//再判断电机速度调节键是否真得按下
{
PWMKeyFlag=1;//置本次按键按下标志成功
temp=MotorPWMData;//读取PWM变量的内容
temp<<=1;//将其转换成0-100之间的占空比
temp/5;
temp++;//占空比加1
if(100==temp)temp=0;//到100归0
LCDBuffer_0[5]=(temp/10)+0x30;//送到LCD缓冲区
LCDBuffer_0[6]=(temp%10)+0x30;
temp*=5;//再将其转换成0-250之间的PWM数据
temp>>=1;
MotorPWMData=temp;//装入PWM变量中
if(0==MotorDirection)//如果电机方向是正转
{
LCDBuffer_0[13]='+';//LCD上显示"+"
CCPR1L=0;
CCPR2L=0;
CCPR1L=MotorPWMData;//PWM变量内容送到CCP1
}
else
{
LCDBuffer_0[13]='-';
CCPR2L=0;
CCPR1L=0;
CCPR2L=MotorPWMData;//PWM变量送到CCP2
}
lcd_displaystr(0,0,LCDBuffer_0);//将字符串送到LCD上显示
}
}
}
}
else
{
if(1==PWMKeyFlag)//等待按键释放
{
PWMKeyFlag=0;//清按键按下标志
PWMKeyCounter=0;//计数器清0
}
}
if((1==FreqFlag)&&(0==CycleFlag))//1S的测频标志成立
{
FreqFlag=0;//清测频标志
temp=MyTMR1.HighCounter;//读取经过测频的计数脉冲
temp<<=16;
temp|=MyTMR1.LowCounter;
//电机速度小于1000RPM,切换到测周法
if(temp<1000)
{
INTCONbits.INT0IE=1;//允许INT0中断允许
INTCONbits.INT0IF=0;//清INT0中断标志位
MyTMR3.ChangeFlag=0;//清测周所用变量标志位
}
else//否则就用测频法计算电机速度
{
INTCONbits.INT0IE=0;//禁止INT0中断允许
INTCONbits.INT0IF=0;//清INT0中断标志位
//将测量的结果显示在LCD显示屏上
for(i=8;i<12;i++)LCDBuffer_1[i]=0x30;
i=11;
while(temp)
{
LCDBuffer_1[i]=(temp%10)+0x30;
temp/=10;
i--;
}
MyTMR1.HighCounter=0;//清TMR1使用的相关变量
MyTMR1.LowCounter=0;
T1CONbits.TMR1ON=1;
lcd_displaystr(1,0,LCDBuffer_1);//将测量的结果送到LCD上显示
}
}
if((1==CycleFlag)&&(0==FreqFlag))
{
CycleFlag=0;
temp=MyTMR3.HighCounter;
temp<<=16;
temp|=MyTMR3.LowCounter;
temp=1000000/temp;
//将测量的结果显示在LCD显示屏上
for(i=8;i<12;i++)LCDBuffer_1[i]=0x30;
i=11;
while(temp)
{
LCDBuffer_1[i]=(temp%10)+0x30;
temp/=10;
i--;
}
MyTMR3.HighCounter=0;
MyTMR3.LowCounter=0;
T1CONbits.TMR1ON=1;
lcd_displaystr(1,0,LCDBuffer_1);//将测量的结果送到LCD上显示
}
}
}
//-------------------------------------------------------------------
#pragma interrupt PIC18F_High_isr
void PIC18F_High_isr(void)
{
unsigned long temp;
if(1==INTCONbits.INT0IF)
{
INTCONbits.INT0IF=0;
if(MyTMR3.ChangeFlag)
{
INTCONbits.INT0IE=0;
MyTMR3.ChangeFlag=0;//如果标志为1,则置0
MyTMR3.LowCounter=TMR3L;//读取TMR3寄存器的内容
MyTMR3.LowCounter=TMR3H;
MyTMR3.LowCounter<<=8;
MyTMR3.LowCounter|=TMR3L;
FreqFlag=0;
CycleFlag=1;
}
else
{
MyTMR3.ChangeFlag=1;//如果标志为0,则置1
MyTMR3.HighCounter=0;//清相关变量
MyTMR3.LowCounter=0;
}
}
if(1==INTCONbits.TMR0IF)//定时1S时间到
{
INTCONbits.TMR0IF=0;//TMR0溢出标志位清0
TMR0H=(65536-31250)/256;//先写高字节
TMR0L=(65536-31250)%256;//再写低字节
T1CONbits.TMR1ON=0;//TMR1计数器停止工作
MyTMR1.LowCounter=TMR1L;
MyTMR1.LowCounter=TMR1H;
MyTMR1.LowCounter<<=8;
MyTMR1.LowCounter|=TMR1L;
CycleFlag=0;
FreqFlag=1;
}
}
//-------------------------------------------------------------------
//---低优先中断服务程序函数
#pragma interruptlow SystemInterruptISR
void SystemInterruptISR(void)
{
if(1==PIR1bits.TMR1IF)//如果TMR1溢出
{
PIR1bits.TMR1IF=0;//清TMR1溢出标志位
MyTMR1.HighCounter++;//TMR1软计数器加1
}
if(1==PIR2bits.TMR3IF)//如果TMR3溢出
{
PIR2bits.TMR3IF=0;//清TMR3溢出标志位
MyTMR3.HighCounter++;//TMR3软计数器加1
}
}
复制代码
0.jpg
(7.54 KB, 下载次数: 112)
下载附件
2018-5-20 02:39 上传
所有资料51hei提供下载:
PIC单片机实用C语言程序设计与典型实例(光盘).rar
(327.06 KB, 下载次数: 221)
2018-5-19 11:24 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
jzyjsjt
时间:
2019-6-18 14:56
感谢楼主分享!
作者:
石进良
时间:
2019-8-23 21:50
感谢楼主分享!
作者:
石进良
时间:
2019-8-23 21:51
感谢楼主分享!
作者:
qxdqx
时间:
2019-12-22 10:37
太好啦谢谢分享!
作者:
xxhei
时间:
2020-4-7 11:21
谢谢 手下了
作者:
花语993715
时间:
2020-5-6 11:31
感谢楼主分享
作者:
jackyjing
时间:
2020-6-4 15:39
感谢楼主分享!
作者:
liesnake
时间:
2021-5-14 15:41
如果有pcb文件就完美了。
作者:
清心阁阁主
时间:
2021-5-17 16:30
不错 不错 很好的资料 感谢分享!!!!!!!!!!!!
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1