朋友问能否用模拟量控制PWM,这么简单当然easy了,我用STC15W408AS的DIP20脚的单片机,因为这种单片机具有AD输入通道和PWM输出,很快做好了一个单通道的实验,完事想这个单片机有三个PWM输出,我可以驱动三色LED进行显示玩玩,用三个电位器控制三色LED的亮度变化就可以输出各种颜色了:
硬件很简单,就是三个10K电位器对电源5V分压,调整端电压进三个AD:P1.0,1.1,1.2,PWM输出在P3.5,3.6,3.7,三色LED红蓝绿正极接一起接5V正极,三个LED负极分别接1K电阻进三个PWM输出,调整电位器分别控制PWM输出驱动LED亮度变化,不同组合就是不同颜色。
C程序如下,大部分摘录自STC的下载工具里面的范例,大部分选项参数并没有清理,原汁原味,当然也有一点错误给予修正:
//STC15W408AS DIP20 11.0592MHz 串口115.2K比特率
//本程序电位器输入三个模拟量,AD结果送串口,同时输出三个PWM驱动三基色LED
//PWM移动到第二输出口,以便让开AD三个输入通道
//PWM设定为8bit输出,AD只取高八位,刚好对应
#include "reg51.h"
#include "intrins.h"
#define FOSC 11059200L
#define BAUD 115200
typedef unsigned char BYTE;
typedef unsigned int WORD;
#define URMD 0 //0:使用定时器2作为波特率发生器
//1:使用定时器1的模式0(16位自动重载模式)作为波特率发生器
//2:使用定时器1的模式2(8位自动重载模式)作为波特率发生器
sfr T2H = 0xd6; //定时器2高8位
sfr T2L = 0xd7; //定时器2低8位
sfr AUXR = 0x8e; //辅助寄存器
sfr ADC_CONTR = 0xBC; //ADC控制寄存器
sfr ADC_RES = 0xBD; //ADC高8位结果
sfr ADC_LOW2 = 0xBE; //ADC低2位结果
sfr P1ASF = 0x9D; //P1口第2功能控制寄存器
#define ADC_POWER 0x80 //ADC电源控制位
#define ADC_FLAG 0x10 //ADC完成标志
#define ADC_START 0x08 //ADC起始控制位
#define ADC_SPEEDLL 0x00 //540个时钟
#define ADC_SPEEDL 0x20 //360个时钟
#define ADC_SPEEDH 0x40 //180个时钟
#define ADC_SPEEDHH 0x60 //90个时钟
sfr P_SW1 = 0xA2; //外设功能切换寄存器1
#define CCP_S0 0x10 //P_SW1.4
#define CCP_S1 0x20 //P_SW1.5
sfr CCON = 0xD8; //PCA控制寄存器
sbit CCF0 = CCON^0; //PCA模块0中断标志
sbit CCF1 = CCON^1; //PCA模块1中断标志
sbit CR = CCON^6; //PCA定时器运行控制位
sbit CF = CCON^7; //PCA定时器溢出标志
sfr CMOD = 0xD9; //PCA模式寄存器
sfr CL = 0xE9; //PCA定时器低字节
sfr CH = 0xF9; //PCA定时器高字节
sfr CCAPM0 = 0xDA; //PCA模块0模式寄存器
sfr CCAP0L = 0xEA; //PCA模块0捕获寄存器 LOW
sfr CCAP0H = 0xFA; //PCA模块0捕获寄存器 HIGH
sfr CCAPM1 = 0xDB; //PCA模块1模式寄存器
sfr CCAP1L = 0xEB; //PCA模块1捕获寄存器 LOW
sfr CCAP1H = 0xFB; //PCA模块1捕获寄存器 HIGH
sfr CCAPM2 = 0xDC; //PCA模块2模式寄存器
sfr CCAP2L = 0xEC; //PCA模块2捕获寄存器 LOW
sfr CCAP2H = 0xFC; //PCA模块2捕获寄存器 HIGH
sfr PCA_PWM0 = 0xf2; //PCA模块0的PWM寄存器
sfr PCA_PWM1 = 0xf3; //PCA模块1的PWM寄存器
sfr PCA_PWM2 = 0xf4; //PCA模块2的PWM寄存器
void InitUart();
void InitADC();
void SendData(BYTE dat);
BYTE GetADCResult(BYTE ch);
void Delay(WORD n);
void ShowResult(BYTE ch);
void main()
{
// ACC = P_SW1;
// ACC &= ~(CCP_S0 | CCP_S1); //CCP_S0=0 CCP_S1=0
// P_SW1 = ACC; //(P1.2/ECI, P1.1/CCP0, P1.0/CCP1, P3.7/CCP2)
ACC = P_SW1;
ACC &= ~(CCP_S0 | CCP_S1); //CCP_S0=1 CCP_S1=0
ACC |= CCP_S0; //(P3.4/ECI_2, P3.5/CCP0_2, P3.6/CCP1_2, P3.7/CCP2_2)
P_SW1 = ACC;
//
// ACC = P_SW1;
// ACC &= ~(CCP_S0 | CCP_S1); //CCP_S0=0 CCP_S1=1
// ACC |= CCP_S1; //(P2.4/ECI_3, P2.5/CCP0_3, P2.6/CCP1_3, P2.7/CCP2_3)
// P_SW1 = ACC;
CCON = 0; //初始化PCA控制寄存器
//PCA定时器停止
//清除CF标志
//清除模块中断标志
CL = 0; //复位PCA寄存器
CH = 0;
CMOD = 0x02; //设置PCA时钟源
//禁止PCA定时器溢出中断
PCA_PWM0 = 0x00; //PCA模块0工作于8位PWM
CCAPM0 = 0x42; //PCA模块0为8位PWM模式
CCAP0H = CCAP0L = 0x00; //PWM0的占空比初值
PCA_PWM1 = 0x00; //PCA模块1工作于8位PWM
CCAPM1 = 0x42; //PCA模块1为8位PWM模式
CCAP1H = CCAP2L = 0x00; //PWM1的占空比初值
PCA_PWM2 = 0x00; //PCA模块2工作于8位PWM
CCAPM2 = 0x42; //PCA模块2为8位PWM模式
CCAP2H = CCAP2L = 0x00; //PWM2的占空比初值
CR = 1; //PCA定时器开始工作
InitUart(); //初始化串口
InitADC(); //初始化ADC
while (1)
{
ShowResult(0); //显示通道0
CCAP0H = CCAP0L = GetADCResult(0);//PWM0输出AD0通道的值
ShowResult(1); //显示通道1
CCAP1H = CCAP1L = GetADCResult(1);//PWM1输出AD1通道的值
ShowResult(2); //显示通道2
CCAP2H = CCAP2L = GetADCResult(2);//PWM2输出AD2通道的值
// ShowResult(3); //显示通道3
// ShowResult(4); //显示通道4
// ShowResult(5); //显示通道5
// ShowResult(6); //显示通道6
// ShowResult(7); //显示通道7
// Delay(10);
}
}
/*----------------------------
发送ADC结果到PC
----------------------------*/
void ShowResult(BYTE ch)
{
SendData(ch); //显示通道号
SendData(GetADCResult(ch)); //显示ADC高8位结果
// SendData(ADC_LOW2); //显示低2位结果
// Delay(20);
}
/*----------------------------
读取ADC结果
----------------------------*/
BYTE GetADCResult(BYTE ch)
{
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
_nop_(); //等待4个NOP
_nop_();
_nop_();
_nop_();
while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成
ADC_CONTR &= ~ADC_FLAG; //Close ADC
return ADC_RES; //返回ADC结果
}
/*----------------------------
初始化串口
----------------------------*/
void InitUart()
{
SCON = 0x5a; //设置串口为8位可变波特率
#if URMD == 0
T2L = (65536 - (FOSC/4/BAUD)); //设置波特率重装值
T2H = (65536 - (FOSC/4/BAUD))>>8;
AUXR = 0x14; //T2为1T模式, 并启动定时器2
AUXR |= 0x01; //选择定时器2为串口1的波特率发生器
#elif URMD == 1
AUXR = 0x40; //定时器1为1T模式
TMOD = 0x00; //定时器1为模式0(16位自动重载)
TL1 = 0xd8; //设置波特率重装值
TH1 = 0xff; //115200 bps(65536-18432000/4/115200)
TR1 = 1; //定时器1开始启动
#else
TMOD = 0x20; //设置定时器1为8位自动重装载模式
AUXR = 0x40; //定时器1为1T模式
TH1 = TL1 = 0xfb; //115200 bps(256 - 18432000/32/115200)
TR1 = 1;
#endif
}
/*----------------------------
初始化ADC
----------------------------*/
void InitADC()
{
P1ASF = 0xff; //设置P1口为AD口
ADC_RES = 0; //清除结果寄存器
ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
Delay(2); //ADC上电并延时
}
/*----------------------------
发送串口数据
----------------------------*/
void SendData(BYTE dat)
{
while (!TI); //等待前一个数据发送完成
TI = 0; //清除发送标志
SBUF = dat; //发送当前数据
}
/*----------------------------
软件延时
----------------------------*/
void Delay(WORD n)
{
WORD x;
while (n--)
{
x = 5000;
while (x--);
}
}
文章评论(0条评论)
登录后参与讨论