找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9388|回复: 9
收起左侧

PIC单片机PWM电机速度控制源码-实用C语言程序设计与典型实例

  [复制链接]
ID:333546 发表于 2018-5-19 11:27 | 显示全部楼层 |阅读模式
与PIC单片机实用C语言程序设计与典型实例书籍配套的光盘实例,包括原理图和C语言程序文件,希望对大家有所帮助!
0.jpg

单片机源程序如下:
  1. #include <p18cxxx.h>
  2. #include "16x2LCDDriver.h"

  3. unsigned char LCDBuffer_0[]={"STOP 00% DIR +"};
  4. unsigned char LCDBuffer_1[]={"Get Spd 0000 RPM"};

  5. struct TMR1COUNTER_STRUCT
  6. {
  7.   unsigned char HighCounter;
  8.   unsigned int LowCounter;       
  9.   unsigned char ChangeFlag;
  10. };
  11. struct TMR1COUNTER_STRUCT MyTMR1,MyTMR3,GetTMR1,GetTMR3;

  12. void OSCillator_Initize(void)
  13. {
  14.   OSCCON=0x70;//选择内部8MHz的主振荡器
  15.   OSCTUNE=0x40;//使能4xPLL--->Fosc=32MHz
  16. }

  17. void PIC_PortDir_Initize(void)
  18. {
  19.   ADCON1=0x0F;//RA和RE端口全为数字IO口
  20.   TRISD=0x00;//RD端口置输出方向
  21.   TRISE=0x00;//RE端口置输出方向
  22.   TRISCbits.TRISC1=0;
  23.   TRISCbits.TRISC2=0;
  24.   TRISCbits.TRISC3=0;
  25. }

  26. void PIC_TMR0_Initize(void)
  27. {
  28.   T0CONbits.TMR0ON=0;//TMR0停止工作
  29.   T0CONbits.T08BIT=0;//选择16位的定时/计数器
  30.   T0CONbits.T0CS=0;//选择内部CLKO时钟源作为定时
  31.   T0CONbits.PSA=0;//选择预分频器
  32.   T0CONbits.T0PS2=1;//预分频比为1:256
  33.   T0CONbits.T0PS1=1;
  34.   T0CONbits.T0PS0=1;
  35.   TMR0H=(65536-31250)/256;//先写高字节
  36.   TMR0L=(65536-31250)%256;//再写低字节
  37.   T0CONbits.TMR0ON=1;//开始定时工作  
  38. }

  39. void PIC_TMR1_Initize(void)
  40. {
  41.   //此处TMR1的预分频比为1:1
  42.   T1CONbits.RD16=1;//允许一次性读写16位
  43.   T1CONbits.TMR1CS=1;//选择外部时钟源,TMR1用作外部计数
  44.   TMR1H=0;//TMR1数据寄存器清0
  45.   TMR1L=0;
  46.   T1CONbits.TMR1ON=1;//允许TMR1开始工作
  47. }

  48. void PIC_TMR3_Initize(void)
  49. {
  50.   //此处TMR1的预分频比为1:8
  51.   T3CONbits.T3CKPS1=1;
  52.   T3CONbits.T3CKPS0=1;
  53.   T3CONbits.RD16=1;//允许一次性读写16位
  54.   T3CONbits.TMR3CS=0;//选择内部时钟源,TMR3用作内部计数
  55.   TMR3H=0;//TMR3数据寄存器清0
  56.   TMR3L=0;
  57.   T3CONbits.TMR3ON=1;//允许TMR3开始工作
  58. }

  59. void PIC_Interrupt_Initize(void)
  60. {
  61.   INTCONbits.TMR0IF=0;//TMR0溢出标志位清0
  62.   INTCONbits.TMR0IE=1;//TMR0溢出中断允许
  63.   
  64.   PIR1bits.TMR1IF=0;//TMR1溢出标志位清0
  65.   PIE1bits.TMR1IE=1;//TMR1溢出中断允许
  66.   IPR1bits.TMR1IP=0;//低优先级
  67.    
  68.   PIR2bits.TMR3IF=0;//TMR1溢出标志位清0
  69.   PIE2bits.TMR3IE=1;//TMR1溢出中断允许
  70.   IPR2bits.TMR3IP=0;//低优先级
  71.   
  72.   INTCONbits.INT0IF=0;//清INT0中断标志位
  73.   //INTCONbits.INT0IE=1;//INT0中断允许
  74.   INTCON2bits.RBPU=0;//允许内部弱上拉
  75.   INTCON2bits.INTEDG0=1;//上边沿触发中断
  76.   
  77.   RCONbits.IPEN=1;//允许中断优先级位
  78.   INTCONbits.GIE=1;//CPU全局中断使能允许
  79.   INTCONbits.PEIE=1;//CPU第二梯队中断使能允许
  80. }

  81. void PIC_CCPForPWM_Initize(void)
  82. {
  83.   TRISCbits.TRISC1=0;//RC1置输出方向
  84.   TRISCbits.TRISC2=0;//RC2置输出方向
  85.   LATCbits.LATC1=0;//RC1引脚输出为0
  86.   LATCbits.LATC2=0;//RC2引脚输出为0
  87.   CCP1CON=0x0F;//CCP1设置为PWM模式
  88.   CCP2CON=0x0F;//CCP2设置为PWM模式
  89.   T2CON=0x03;//TMR2的预分频为1:16
  90.   T2CONbits.TMR2ON=1;//TMR2开始工作
  91.   PR2=249;//PWM周期为2000Hz,FOSC=32MHz
  92.   CCPR1L=0;//PWM1的占空比为0
  93.   CCPR2L=0;//PWM2的占空比为0         
  94. }

  95. unsigned char CycleFlag;
  96. unsigned char FreqFlag;

  97. #define RUNSTOPKEY PORTBbits.RB3
  98. #define PWMKEY PORTBbits.RB4
  99. #define DIRKEY PORTBbits.RB5

  100. unsigned char MotorRunStatus;
  101. unsigned char MotorDirection;
  102. unsigned char MotorPWMData;
  103. unsigned char RunStopKeyFlag;
  104. unsigned int RunStopKeyCounter;
  105. unsigned char DirKeyFlag;
  106. unsigned int DirKeyCounter;
  107. unsigned char PWMKeyFlag;
  108. unsigned int PWMKeyCounter;


  109. void SystemVariant_Initize(void)
  110. {
  111.   MotorPWMData=0;         
  112. }

  113. void Motor_Control(unsigned char Direction,
  114.                    unsigned char Speed)
  115. {
  116.   switch(Direction)
  117.     {
  118.           case 0:
  119.             CCPR1L=0;
  120.             CCPR2L=0;
  121.             CCPR1L=Speed;
  122.             break;
  123.           case 1:
  124.             CCPR2L=0;
  125.             CCPR1L=0;
  126.             CCPR2L=Speed;
  127.             break;
  128.         }       
  129. }

  130. //-------------------------------------------------------------------
  131. void PIC18F_High_isr(void);//高优先级中断函数声明
  132. #pragma code high_vector_section=0x8
  133. void high_vector (void)
  134. {
  135.   _asm goto PIC18F_High_isr _endasm
  136. }
  137. void SystemInterruptISR(void);//低优先级中断函数声明
  138. #pragma code low_vector=0x18//低中断优先级
  139. void low_interrupt(void)
  140. {
  141.   _asm goto SystemInterruptISR _endasm       
  142. }
  143. #pragma code
  144. //-------------------------------------------------------------------


  145. void main(void)
  146. {
  147.   unsigned long temp;
  148.   unsigned char i;
  149.   
  150.   OSCillator_Initize();//CPU系统时钟初始化内部时钟源8MHz,经过4xPLL
  151.   PIC_PortDir_Initize();//PIC单片机的使用到的I/O口方向初始化
  152.   PIC_TMR0_Initize();//PIC单片机的TMR0定时器初始化为内部定时方式
  153.   PIC_TMR1_Initize();//PIC单片机的TMR1定时器初始化为外部计数方式
  154.   PIC_TMR3_Initize();
  155.   PIC_CCPForPWM_Initize();
  156.   PIC_Interrupt_Initize();
  157.   initize_lcd();
  158.   
  159.   while(1)
  160.     {
  161.           if(0==RUNSTOPKEY)//判断启动按键是否按下
  162.             {
  163.                   if(0==RunStopKeyFlag)//检测启动按键是否成功按下标志
  164.                     {
  165.                           RunStopKeyCounter++;//软件计数器,用于按键去抖动
  166.                           if(4000==RunStopKeyCounter)//按键去抖动延时到
  167.                             {
  168.                                   RunStopKeyCounter=0;//清软计数器为0
  169.                                   if(0==RUNSTOPKEY)//再判断启动按键是否真得按下
  170.                                     {
  171.                                           RunStopKeyFlag=1;//置启动按键成功按下标志为1
  172.                                           if(0==MotorRunStatus)//如果电机是处理停止状态
  173.                                             {//则启动电机运转
  174.                                                     MotorRunStatus=1;//同时置电机状态为1                                                 
  175.                                                 LCDBuffer_0[0]='R';//LCD显示屏上显示"RUN"
  176.                                           LCDBuffer_0[1]='U';
  177.                                           LCDBuffer_0[2]='N';
  178.                                           LCDBuffer_0[3]=' ';
  179.                                           LCDBuffer_0[4]=' ';
  180.                                               temp=MotorPWMData;//读取设置电机速度的变量
  181.                                               temp<<=1;//转换成占空比送到LCD上显示
  182.                                               temp/=5;
  183.                                               LCDBuffer_0[5]=(temp/10)+0x30;
  184.                                               LCDBuffer_0[6]=(temp%10)+0x30;
  185.                                               LCDBuffer_0[7]='%';
  186.                                               LCDBuffer_0[8]=' ';
  187.                                               LCDBuffer_0[9]='D';
  188.                                               LCDBuffer_0[10]='I';
  189.                                               LCDBuffer_0[11]='R';
  190.                                               LCDBuffer_0[12]=' ';
  191.                                                     if(0==MotorDirection)//根据电机运转的方向
  192.                                                       {//来设置电机是正转还是反转,并在LCD上显示
  193.                                                         CCPR1L=0;
  194.                                                         CCPR2L=0;
  195.                                                         CCPR1L=MotorPWMData;//使RC1引脚输出PWM信号
  196.                                                         LCDBuffer_0[13]='+';//表示电机正转
  197.                                                           }
  198.                                                           else
  199.                                                             {
  200.                                                           CCPR2L=0;
  201.                                                           CCPR1L=0;
  202.                                                           CCPR2L=MotorPWMData;//使RC2引脚输出PWM信号
  203.                                                           LCDBuffer_0[13]='-';//表示电机反转
  204.                                                         }                                                                                                   
  205.                                                   }
  206.                                                   else//如果电机是在运转中,则这时按下该键可以停止电机运转
  207.                                                     {
  208.                                                       MotorRunStatus=0;//置电机运动状态为0
  209.                                                   LCDBuffer_0[0]='S';//LCD屏上显示"STOP"
  210.                                             LCDBuffer_0[1]='T';
  211.                                             LCDBuffer_0[2]='O';
  212.                                             LCDBuffer_0[3]='P';
  213.                                             LCDBuffer_0[4]=' ';       
  214.                                             LCDBuffer_0[5]='0';
  215.                                             LCDBuffer_0[6]='0';            
  216.                                                       CCPR1L=0;//RC1和RC2引脚不输出PWM信号
  217.                                                       CCPR2L=0;          
  218.                                                     }
  219.                                           lcd_displaystr(0,0,LCDBuffer_0);//将字符串送到LCD上显示
  220.                                         }                                  
  221.                                 }  
  222.                         }
  223.                 }
  224.                 else
  225.                   {
  226.                         if(1==RUNSTOPKEY)//等待按键释放处理过程
  227.                           {
  228.                                  if(1==RunStopKeyFlag)
  229.                                    {
  230.                                      RunStopKeyFlag=0;//清启动按键上次成功按下标志
  231.                                      RunStopKeyCounter=0;//消抖动延时计数器清0
  232.                                    }
  233.                       }                                  
  234.               }   
  235.                
  236.           if(0==DIRKEY)//判断电机运转方向切换键是否按下
  237.             {
  238.                   if(0==DirKeyFlag)//判断方向切换键的标志是否成功
  239.                     {
  240.                           DirKeyCounter++;//去抖动计数器加1
  241.                           if(4000==DirKeyCounter)//去抖动延时时间到
  242.                             {
  243.                                   DirKeyCounter=0;//计数器清0
  244.                                   if(0==DIRKEY)//判断是否真得按下
  245.                                     {
  246.                                           DirKeyFlag=1;//置成功按下标志成立
  247.                                           if(0==MotorDirection)//电机是正转方向吗?
  248.                                             {
  249.                                                   MotorDirection=1;//置反向运转方向状态
  250.                                                   LCDBuffer_0[13]='-';//LCD显示屏显示"-"
  251.                                                   CCPR2L=0;
  252.                                                   CCPR1L=0;
  253.                                                   CCPR2L=MotorPWMData;//启动RC2输出PWM信号
  254.                                                 }
  255.                                             else
  256.                                               {
  257.                                                     MotorDirection=0;//置正向运转方向状态
  258.                                                     LCDBuffer_0[13]='+';//LCD显示屏上显示"+"
  259.                                                     CCPR1L=0;
  260.                                                     CCPR2L=0;
  261.                                                     CCPR1L=MotorPWMData;//启运RC1输出PWM信号
  262.                                                   }
  263.                                       lcd_displaystr(0,0,LCDBuffer_0);//将字符串送到LCD上显示
  264.                                         }                                  
  265.                                 }
  266.                         }
  267.                 }
  268.                 else
  269.                   {
  270.                         if(1==DIRKEY)//等待按键释放
  271.                           {
  272.                                 if(1==DirKeyFlag)//如果上次按键按下标志成功,则
  273.                                   {
  274.                                     DirKeyFlag=0;//清按键按下标志
  275.                                     DirKeyCounter=0;//清计数器为0
  276.                                   }
  277.                       }
  278.               }
  279.           
  280.           if(0==PWMKEY)//判断电机速度调节键是否按下
  281.             {
  282.                   if(0==PWMKeyFlag)//判断按键按下标志是否为0
  283.                     {
  284.                           PWMKeyCounter++;//去抖动计数器加1
  285.                           if(4000==PWMKeyCounter)//支抖动延时时间到
  286.                             {
  287.                                   PWMKeyCounter=0;//清计数器为0
  288.                                   if(0==PWMKEY)//再判断电机速度调节键是否真得按下
  289.                                     {
  290.                                           PWMKeyFlag=1;//置本次按键按下标志成功
  291.                                           temp=MotorPWMData;//读取PWM变量的内容
  292.                                           temp<<=1;//将其转换成0-100之间的占空比
  293.                                           temp/5;
  294.                                           temp++;//占空比加1
  295.                                           if(100==temp)temp=0;//到100归0
  296.                                           LCDBuffer_0[5]=(temp/10)+0x30;//送到LCD缓冲区
  297.                                           LCDBuffer_0[6]=(temp%10)+0x30;
  298.                                           temp*=5;//再将其转换成0-250之间的PWM数据
  299.                                           temp>>=1;
  300.                                           MotorPWMData=temp;//装入PWM变量中                                          
  301.                                           if(0==MotorDirection)//如果电机方向是正转
  302.                                             {
  303.                                                   LCDBuffer_0[13]='+';//LCD上显示"+"
  304.                                                   CCPR1L=0;
  305.                                                   CCPR2L=0;
  306.                                                   CCPR1L=MotorPWMData;//PWM变量内容送到CCP1
  307.                                                 }
  308.                                             else
  309.                                               {
  310.                                                     LCDBuffer_0[13]='-';
  311.                                                     CCPR2L=0;
  312.                                                     CCPR1L=0;
  313.                                                     CCPR2L=MotorPWMData;//PWM变量送到CCP2
  314.                                                   }
  315.                                           lcd_displaystr(0,0,LCDBuffer_0);//将字符串送到LCD上显示
  316.                                         }
  317.                                 }                               
  318.                         }
  319.                 }
  320.                 else
  321.                   {
  322.                         if(1==PWMKeyFlag)//等待按键释放
  323.                           {
  324.                                 PWMKeyFlag=0;//清按键按下标志
  325.                                 PWMKeyCounter=0;//计数器清0
  326.                       }
  327.               }
  328.           
  329.           if((1==FreqFlag)&&(0==CycleFlag))//1S的测频标志成立
  330.             {
  331.                   FreqFlag=0;//清测频标志
  332.           temp=MyTMR1.HighCounter;//读取经过测频的计数脉冲
  333.           temp<<=16;
  334.           temp|=MyTMR1.LowCounter;
  335.           //电机速度小于1000RPM,切换到测周法
  336.           if(temp<1000)
  337.             {             
  338.                   INTCONbits.INT0IE=1;//允许INT0中断允许
  339.                   INTCONbits.INT0IF=0;//清INT0中断标志位
  340.                   MyTMR3.ChangeFlag=0;//清测周所用变量标志位
  341.                 }
  342.                 else//否则就用测频法计算电机速度
  343.                   {                        
  344.                         INTCONbits.INT0IE=0;//禁止INT0中断允许
  345.                         INTCONbits.INT0IF=0;//清INT0中断标志位
  346.                         //将测量的结果显示在LCD显示屏上
  347.                         for(i=8;i<12;i++)LCDBuffer_1[i]=0x30;
  348.                         i=11;
  349.                         while(temp)
  350.                           {
  351.                                 LCDBuffer_1[i]=(temp%10)+0x30;
  352.                                 temp/=10;
  353.                                 i--;
  354.                               }
  355.                         MyTMR1.HighCounter=0;//清TMR1使用的相关变量
  356.                         MyTMR1.LowCounter=0;
  357.                         T1CONbits.TMR1ON=1;
  358.                         lcd_displaystr(1,0,LCDBuffer_1);//将测量的结果送到LCD上显示
  359.                       }                  
  360.                 }
  361.                
  362.           if((1==CycleFlag)&&(0==FreqFlag))
  363.             {
  364.                   CycleFlag=0;
  365.           temp=MyTMR3.HighCounter;
  366.           temp<<=16;
  367.           temp|=MyTMR3.LowCounter;
  368.           temp=1000000/temp;
  369.           //将测量的结果显示在LCD显示屏上
  370.               for(i=8;i<12;i++)LCDBuffer_1[i]=0x30;
  371.               i=11;
  372.               while(temp)
  373.                 {
  374.                   LCDBuffer_1[i]=(temp%10)+0x30;
  375.                   temp/=10;
  376.                   i--;
  377.                 }         
  378.                   MyTMR3.HighCounter=0;
  379.                   MyTMR3.LowCounter=0;
  380.                   T1CONbits.TMR1ON=1;
  381.                   lcd_displaystr(1,0,LCDBuffer_1);//将测量的结果送到LCD上显示
  382.                 }
  383.         }
  384. }


  385. //-------------------------------------------------------------------
  386. #pragma interrupt PIC18F_High_isr
  387. void PIC18F_High_isr(void)
  388. {
  389.   unsigned long temp;
  390.   
  391.   if(1==INTCONbits.INT0IF)
  392.     {
  393.           INTCONbits.INT0IF=0;
  394.           if(MyTMR3.ChangeFlag)
  395.             {
  396.                   INTCONbits.INT0IE=0;
  397.                   MyTMR3.ChangeFlag=0;//如果标志为1,则置0
  398.                   MyTMR3.LowCounter=TMR3L;//读取TMR3寄存器的内容
  399.                   MyTMR3.LowCounter=TMR3H;
  400.                   MyTMR3.LowCounter<<=8;
  401.                   MyTMR3.LowCounter|=TMR3L;
  402.                   FreqFlag=0;
  403.                   CycleFlag=1;                  
  404.                 }
  405.                 else
  406.                   {
  407.                         MyTMR3.ChangeFlag=1;//如果标志为0,则置1
  408.                         MyTMR3.HighCounter=0;//清相关变量
  409.                         MyTMR3.LowCounter=0;
  410.               }
  411.         }
  412.        
  413.   if(1==INTCONbits.TMR0IF)//定时1S时间到
  414.     {
  415.           INTCONbits.TMR0IF=0;//TMR0溢出标志位清0
  416.       TMR0H=(65536-31250)/256;//先写高字节
  417.       TMR0L=(65536-31250)%256;//再写低字节
  418.       
  419.       T1CONbits.TMR1ON=0;//TMR1计数器停止工作
  420.       MyTMR1.LowCounter=TMR1L;
  421.       MyTMR1.LowCounter=TMR1H;
  422.       MyTMR1.LowCounter<<=8;
  423.       MyTMR1.LowCounter|=TMR1L;
  424.       CycleFlag=0;
  425.       FreqFlag=1;
  426.         }
  427. }

  428. //-------------------------------------------------------------------
  429. //---低优先中断服务程序函数
  430. #pragma interruptlow SystemInterruptISR
  431. void SystemInterruptISR(void)
  432. {
  433.   if(1==PIR1bits.TMR1IF)//如果TMR1溢出
  434.     {
  435.           PIR1bits.TMR1IF=0;//清TMR1溢出标志位
  436.           MyTMR1.HighCounter++;//TMR1软计数器加1
  437.         }
  438.        
  439.   if(1==PIR2bits.TMR3IF)//如果TMR3溢出
  440.     {
  441.           PIR2bits.TMR3IF=0;//清TMR3溢出标志位
  442.           MyTMR3.HighCounter++;//TMR3软计数器加1
  443.         }       
  444. }
复制代码
0.jpg
所有资料51hei提供下载:
PIC单片机实用C语言程序设计与典型实例(光盘).rar (327.06 KB, 下载次数: 218)
回复

使用道具 举报

ID:242092 发表于 2019-6-18 14:56 | 显示全部楼层
感谢楼主分享!
回复

使用道具 举报

ID:339788 发表于 2019-8-23 21:50 | 显示全部楼层
感谢楼主分享!
回复

使用道具 举报

ID:339788 发表于 2019-8-23 21:51 | 显示全部楼层
感谢楼主分享!
回复

使用道具 举报

ID:140183 发表于 2019-12-22 10:37 | 显示全部楼层
太好啦谢谢分享!
回复

使用道具 举报

ID:116743 发表于 2020-4-7 11:21 | 显示全部楼层
谢谢 手下了
回复

使用道具 举报

ID:745141 发表于 2020-5-6 11:31 | 显示全部楼层
感谢楼主分享
回复

使用道具 举报

ID:606233 发表于 2020-6-4 15:39 | 显示全部楼层
感谢楼主分享!
回复

使用道具 举报

ID:319585 发表于 2021-5-14 15:41 来自手机 | 显示全部楼层
如果有pcb文件就完美了。
回复

使用道具 举报

ID:203380 发表于 2021-5-17 16:30 | 显示全部楼层
不错 不错   很好的资料   感谢分享!!!!!!!!!!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表