基于PIC 16F877A的呼吸灯的实现+Proteus的仿真
前言
在学习的PWM模块的过程中,见到论坛中关于PIC单片机的呼吸灯的帖子很少,然后就自己试着做了一下这实验。因为最近在学PIC 16F877A的CCP模块,就想着PIC单片机有着集成的硬件PWM模块,那么好的功能,不能浪费了。于是写下这篇帖子希望可以帮助到一些跟我一样的萌新。
一、如何实现呼吸灯
(1)呼吸灯的原理,通俗的说就是利用PWM波的占空比的变化,让其输出的电压的有效值变化使得LED灯的亮度发送变化(灯泡的亮度是由有效值来确定的),然后通过延时让消除由PWM波占空比带来的闪烁影响。(关于如何产生一个PWM波可以看下这篇文章:https://blog.****.net/cxj7878789/article/details/108165096)
(2)j简单的介绍下使用的软件。
编程软件:MPLAC X IDE
仿真软件:PRTEUS 8.9
(3)j简单的介绍下使用的寄存器。
1)T2CON寄存器。
在CCP_PWM模块中要使用到定时器T2,来产生PWM的周期和脉冲宽度.
设置成T2CON=0X04 //初始化定时器T2,预分频设置为1:1
2)CCP1CON寄存器。
这个寄存器是用来设置PWM波10位分辨率的低2位和开启PWM模式用的。
设置成 CCP1CON=0X3C。 //初始化CCP_PWM让10位分辨率的低两位为11,开启PWM模式
3)PR2寄存器
这个寄存器是用来设置PWM波的周期的。
设置成 PR2=99。这样带入公式中得到的PWM波的周期为:100ns。
4)CCPR1L寄存器。
这个寄存器是用来改变占空比的。(故初始的PWM波的10位分辨率是CCPR1L:CCP1CON<5;4>=0B0000 0000 11)
5)方向寄存器TRISC
这个寄存器是用来设置PORTC口的输入/输出的。
可以直接设置成TRISC=0X00;
也可以按照下图的步骤来设置。(个人习惯我是按照下图来产生PWM波的)
6)法一:采用软件延时法的源代码
#include <xc.h>
void init_pwm();
void delayms(unsigned char x);
void light_control();
unsigned char flag=0;
unsigned int temp=0;
void main(void) {
TRISD=0X00;
PORTD=0X00;
init_pwm();
while(1)
{
light_control();
}
return;
}
void delayms(unsigned char x)
{
unsigned int a,b;
for(a=x;a>0;a--)
for(b=110;b>0;b--);
}
void init_pwm()
{
T2CON=0X04; //初始化定时器T2,预分频设置为1:1
CCP1CON=0X3C;//初始化CCP_PWM让10位分辨率的低两位为11,开启PWM模式
CCPR1L=0X00; //初始化这个寄存器为0x00,是为在后面的程序中通过改变CCPR1L来改变占空比以改变电压的有效值,进而改变LED灯的亮度
PR2=99;
TRISC=0XFF;
TMR2IF=0;
while(!TMR2IF);
TRISC=0;
}
void light_control()
{
delayms(1);
if(flag==0)
{
CCPR1L++;
}
else
{
CCPR1L--;
}
temp=CCPR1L;
if(temp==0X64)
flag=1;
if(temp==0X00)
flag=0;
}
7)法二:采用定时器延时的方法的源代码。
// PIC16F877A Configuration Bit Settings
// 'C' source line config statements
// CONFIG
#pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
这上面的是 MPLAB X IDE的配置位,可能因为软件的不同会出现不同的情况。
#include <xc.h>
void init_pwm();
void delayms(unsigned char x);
void light_control();
unsigned char i=0;
unsigned int num=0;
void main(void) {
init_pwm();
while(1)
{
if(num==5)
{
light_control();
num=0;
}
}
return;
}
void delayms(unsigned char x)
{
unsigned int a,b;
for(a=x;a>0;a--)
for(b=110;b>0;b--);
}
void init_pwm()
{
ADCON1=0X07;
INTCON=0XE0;
OPTION_REG=0X80;
TMR0=0X06;
T2CON=0X04; //初始化定时器T2,预分频设置为1:1
CCP1CON=0X3C;//初始化CCP_PWM让10位分辨率的低两位为11,开启PWM模式
CCPR1L=0X00; //初始化这个寄存器为0x00,是为在后面的程序中通过改变CCPR1L来改变占空比以改变电压的有效值,进而改变LED灯的亮度
PR2=99;
TRISC=0XFF;
TMR2IF=0;
while(!TMR2IF);
TMR2IF=0;
TRISC=0;
}
void light_control()
{
if(i==0)
CCPR1L++;
if(i==1)
CCPR1L--;
if(CCPR1L==0X63)
//特别注意:在设置这个CCPR1L的上限值时,一定要根据PR2来计算出PWM的周期后在设置,例如:我是用的PR2=99,得到的是PWM的周期为100ns,所有带入脉冲宽度公式得到是(CCPR1L:CCP1CON<5:4>)=400=0B0001 1001 00 00。
所有CCPR1L=0110 0100=0X64,因为开始设置CCP1CON=0X3C,低两位为11,所以为了方便设置成,CCPR1L=0x63
(CCPR1L:CCP1CON<5:4>)=0001 1000 11 11=399,误差不大,可以接受。
i=1;SU
if(CCPR1L==0X00)
i=0;
}
void interrupt T0()
{
if(T0IF==1)
{
T0IF=0;
num++;
}
}
二、proteus电路的搭建
(1)元器件的选择
(2)电路的搭建
实验效果
实验效果本来用视频来体现是最好的,但是本人不太会上传视频。抱歉。。。。
所有只能用截图来体现了: