作者:Whappy
个人理解:将电压或电流信号进行等分或不等分(高电平的电压范围和低电平的范围,如0-5v,0-1.8位低电平,3.8-5v为高电平),同样也是通过采样,量化等操作将不连续的数字量进行模拟化。(实际转换中精度很重要!)本实验通过PWM实现
DA:常用T型电阻网络事项
AD:常用逐次逼近型AD转化器
采用PWM来实现数字信号到模拟信号的编码!(也可以说PWM是一种对模拟信号的编码方法)
(在这个DA存在交直流分量,我们只需要直流分量)采用二阶低通滤波器截止频率较低,作用就是将交流分量滤除!(由于低通滤波器的驱动能力也很弱,后面加一个电压跟随器,增大驱动能力)
main.c
/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net
PRECHIN
普中
实验名称:DAC模数转换实验
接线说明:
实验现象:下载程序后,DAC(PWM)模块上的指示灯DA1呈呼吸灯效果,由暗变亮再由亮变暗
注意事项:
***************************************************************************************/
#include "public.h"
#include "pwm.h"
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
u8 dir=0;//默认为0
u8 duty=0;
pwm_init(0XFF,0XF6,100,0);//定时时间为0.01ms,PWM周期是100*0.01ms=1ms,占空比为0%
while(1)
{
if(dir==0)//当dir为递增方向
{
duty++;//占空比递增
if(duty==70)dir=1;//当到达一定值切换方向,占空比最大能到100,但到达70左右再递增,
//肉眼也分辨不出亮度变化
}
else
{
duty--;
if(duty==0)dir=0;//当到达一定值切换方向
}
pwm_set_duty_cycle(duty);//设置占空比
delay_ms(1);//短暂延时,让呼吸灯有一个流畅的效果
}
}
PWM.c
#include "pwm.h"
//全局变量定义
u8 gtim_h=0;//保存定时器初值高8位
u8 gtim_l=0;//保存定时器初值低8位
u8 gduty=0;//保存PWM占空比
u8 gtim_scale=0;//保存PWM周期=定时器初值*tim_scale
/*******************************************************************************
* 函 数 名 : pwm_init
* 函数功能 : PWM初始化函数
* 输 入 : tim_h:定时器高8位
tim_l:定时器低8位
tim_scale:PWM周期倍数:定时器初值*tim_scale
duty:PWM占空比(要小于等于tim_scale)
* 输 出 : 无
*******************************************************************************/
void pwm_init(u8 tim_h,u8 tim_l,u16 tim_scale,u8 duty)
{
gtim_h=tim_h;//将传入的初值保存在全局变量中,方便中断函数继续调用
gtim_l=tim_l;
gduty=duty;
gtim_scale=tim_scale;
TMOD|=0X01; //选择为定时器0模式,工作方式1
TH0 = gtim_h; //定时初值设置
TL0 = gtim_l;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
/*******************************************************************************
* 函 数 名 : pwm_set_duty_cycle
* 函数功能 : PWM设置占空比
* 输 入 : duty:PWM占空比(要小于等于tim_scale)
* 输 出 : 无
*******************************************************************************/
void pwm_set_duty_cycle(u8 duty)
{
gduty=duty;
}
void pwm(void) interrupt 1 //定时器0中断函数
{
static u16 time=0;
TH0 = gtim_h; //定时初值设置
TL0 = gtim_l;
time++;
if(time>=gtim_scale)//PWM周期=定时器初值*gtim_scale,重新开始计数
time=0;
if(time<=gduty)//占空比
PWM=1;
else
PWM=0;
}
代码思路
该代码实现了一个 PWM(脉宽调制)控制的呼吸灯,通过 DAC 模数转换 来控制灯的亮度。主要原理是通过调节 PWM 占空比(duty cycle)来实现灯的亮度从暗到亮,再从亮到暗的逐渐变化,产生呼吸灯的效果。
主要工作原理:
-
PWM 信号的占空比控制输出设备(此处为LED)的亮度。
-
通过递增或递减占空比,模拟灯光由暗到亮再由亮到暗的变化,形成呼吸灯效果。
-
使用定时器周期性地产生中断,并在中断中根据当前占空比控制 LED 的开关状态。
代码实现的主要方法
-
全局变量的使用:
-
gtim_h
和gtim_l
:保存定时器的初值,设定定时器0的初始计数值。 -
gduty
:当前 PWM 的占空比,控制灯亮度。 -
gtim_scale
:PWM 周期长度,由定时器初值与该变量相乘得到。
-
-
PWM初始化函数 (
pwm_init()
):-
该函数初始化定时器0,用于生成 PWM 信号。通过设置定时器的初值以及周期倍数
tim_scale
来控制 PWM 信号的频率。 -
开启定时器和中断,开始产生 PWM 信号。
-
-
占空比设置函数 (
pwm_set_duty_cycle()
):-
该函数用于设置 PWM 信号的占空比,从而控制输出设备(LED)的亮暗变化。占空比的范围为
0
到tim_scale
。
-
-
定时器中断服务函数 (
pwm()
):-
每次定时器0产生中断时会执行该函数。
-
通过计数器
time
记录定时器溢出的次数。当time
小于占空比时,输出高电平(点亮LED);当time
超过占空比时,输出低电平(熄灭LED)。 -
time
从0递增到gtim_scale
,表示一个完整的 PWM 周期。
-
-
主函数 (
main()
):-
主函数控制占空比的递增和递减,使得 LED 亮度随着时间逐渐增加和减小,形成呼吸灯效果。
-
使用
dir
变量控制递增或递减方向,当占空比达到70时改变方向(因为人眼对亮度的变化在某个范围内不再敏感)。 -
delay_ms(1)
用于在占空比每次变化时稍作延时,使得呼吸灯效果更加平滑。
-
实现思路
-
PWM控制亮度:
-
通过定时器0定时产生中断,利用占空比控制 PWM 信号的高低电平。高电平时间越长,LED 越亮;高电平时间越短,LED 越暗。
-
-
呼吸灯效果:
-
通过在主循环中不断改变占空比,使灯光的亮度呈现由暗变亮、由亮变暗的循环变化。
-
-
定时器中断机制:
-
定时器中断周期性触发,根据设定的 PWM 周期和占空比控制输出,确保 PWM 信号的精准性。
-
代码的主要好处
-
高效性:通过定时器和中断机制,系统可以在不占用主程序的情况下精准地产生 PWM 信号,减少 CPU 负载。
-
流畅性:通过逐渐改变占空比,呼吸灯效果十分平滑,不会出现明显的亮暗突变。
-
可调性:通过设置不同的 PWM 周期和占空比范围,可以很方便地调节 LED 的亮暗周期和呼吸灯效果。
总结
该代码展示了如何利用51单片机定时器和中断功能生成 PWM 信号,从而控制 LED 的亮度变化,最终实现呼吸灯效果。通过精确的时间控制和占空比调节,实现了灯光的渐变效果,具备良好的流畅性和稳定性。