2019-06-11 16:54:44 weixin_38679924 阅读数 1279
  • 巫妖王51单片机开发板配套视频课程

    本课程是巫妖王51单片机开发板的配套视频课程,本课程的目标是用少的时间带大家初级入门51单片机。配合巫妖王51单片机开发板,让大家花费少的时间少的钱就能轻松开启单片机学习之路。

    18609 人正在学习 去看看 朱有鹏

项目描述:
由三个按键分别控制LED的开关、变亮、变暗。灯的亮度调节采用单片机产生的PWM实现。
C语言代码如下:

/*-----------------------------
FileName:PWMDimming.h
Function: 头文件
Author: Zhang Kaizhou
Date: 2019-6-11 16:49:42
------------------------------*/
#include <reg52.h>
#include <string.h>
#define uchar unsigned char
#define uint unsigned int
#define PERIOD 100 // PWM信号周期为 100ms

/*主模块端口定义*/
sbit led = P1^7;
sbit onOff = P3^4;
sbit addLight = P3^5;
sbit decLight = P3^6;

/*LCD1602显示模块端口定义*/
sbit lcdrs = P1^0;
sbit lcdrw = P1^1;
sbit lcden = P2^5;

/*主模块函数声明*/
void delay(uint xms);
void keyScan();
void dimming();
void generatePWM();

/*LCD1602显示模块函数声明*/
void LCDInit();
void display(uchar dat);
void writeCommand(uchar command);
void writeData(uchar dat);
/*-------------------------------------------------
Function: 单片机PWM调光
Description: 按键控制LED灯开关,四个亮度等级的调光;
LCD1602实时显示LED灯的亮度等级。
Author: Zhang Kaizhou
Date: 2019-6-11 15:37:10
--------------------------------------------------*/
#include "PWMDimming.h"

/*全局变量定义*/
uchar brightness = 0; // 亮度标志
uint count = 0;
bit onFlag = 0; // 0-关灯 1-开灯

void main(){
	LCDInit();
	led = 1; // 上电时灯处于关闭状态
	while(1){
		keyScan();
		display(brightness);
		dimming();
		generatePWM();
	}
}

/*键盘扫描函数*/
void keyScan(){
	if(!onOff){ // 开关灯
		delay(5);
		if(!onOff){
			while(!onOff);
			led = onFlag;
			onFlag = ~onFlag;
			if(onFlag){
				brightness = 1; // 开灯初始亮度为1
			}else{
				brightness = 0;
				led = 1;
			}
		}
	}else if(onFlag){ // 灯处于开的状态
		if(!addLight){ // 变亮
			delay(5);
			if(!addLight){
				if(brightness < 4){
					while(!addLight);
					brightness++;
				}
			}
		}
		if(!decLight){ // 变暗
			delay(5);
			if(!decLight){
				if(brightness > 1){
					while(!decLight);
					brightness--;
				}
			}
		}
	}
}

/*调光程序*/
void dimming(){
	switch(brightness){
		case 1: count = 80; break; // 80%占空比
		case 2: count = 90; break; // 90%占空比
		case 3: count = 95; break; // 95%占空比
		case 4: count = 100; break; // 100%占空比
		default: break;
	}
}

/*产生PWM信号*/
void generatePWM(){
	while(onOff && addLight && decLight && brightness){
		led = 0;
		delay(count);
		led = 1;
		delay(PERIOD - count);
	}
}

/*延时函数*/
void delay(uint xms){
	uint i, j;
	for(i = xms; i > 0; i--)
		for(j = 110; j > 0; j--);
}
/*-----------------------------
FileName:display.c
Function: LCD1602显示函数
Author: Zhang Kaizhou
Date: 2019-6-11 16:49:02
------------------------------*/
#include "PWMDimming.h"
/*显示信息数组*/
uchar code table0[] = {"PWMDmimming"};
uchar code table1[] = {"Brightness:"};
uchar code table2[] = {"01234"};
uchar num = 0;

/*初始化LCD1602的设置*/
void LCDInit(){
	uchar i;
	lcden = 0; // 拉低使能端,准备产生使能高脉冲信号
	writeCommand(0x38); // 显示模式设置(16x2, 5x7点阵,8位数据接口)
	writeCommand(0x0c); // 开显示,不显示光标
	writeCommand(0x06); // 写一个字符后地址指针自动加1
	writeCommand(0x01); // 显示清零,数据指针清零
	
	/*LCD上电界面*/
	writeCommand(0x80); // 将数据指针定位到第一行首
	for(i = 0; i < strlen(table0); i++){
		writeData(table0[i]);
		delay(5);
	}
	
	writeCommand(0x80 + 0x40); // 将数据指针定位到第二行首
	for(i = 0; i < strlen(table1); i++){
		writeData(table1[i]);
		delay(5);
	}
}

/*LCD显示函数*/
void display(uchar dat){
	writeCommand(0x80 + 0x40 + strlen(table1));
	writeData(table2[dat]);
	delay(5);
}

/*写指令函数*/
void writeCommand(uchar command){
	lcdrs = 0; // 命令选择
	lcdrw = 0;
	P0 = command;
	delay(5);
	
	lcden = 1; // 产生一个正脉冲使能信号
	delay(5);
	lcden = 0;
}

/*写数据函数*/
void writeData(uchar dat){
	lcdrs = 1; // 数据选择
	lcdrw = 0;
	P0 = dat;
	delay(5);
	
	lcden = 1;
	delay(5);
	lcden = 0;
}

扩展:
1.可根据需求增加或减少LED灯的亮度等级;
2.可通过改变个亮度等级对应的PWM的占空比来改变个亮度等级对应的灯的亮度;
3.因为此处PWM调制主要是根据占空比的不同控制LED的亮度,因此用软件延时即可。

2019-01-06 13:41:14 weixin_44017446 阅读数 4659
  • 巫妖王51单片机开发板配套视频课程

    本课程是巫妖王51单片机开发板的配套视频课程,本课程的目标是用少的时间带大家初级入门51单片机。配合巫妖王51单片机开发板,让大家花费少的时间少的钱就能轻松开启单片机学习之路。

    18609 人正在学习 去看看 朱有鹏

PWM输出

学期快结束了,51单片机的学习也差不多告一段落,也快要转入新的学习阶段,寒假找个时间看看32,小白哈哈哈,下面是我学习51定时器弄出来的小东西,一个PWM的输出。还请大神指点。

刚开始觉得PWM输出应该不难,很容易做的,但是后面越像越多,就感觉其实做不来不难,做精确才难,刚开始想到的用一个定时器做,也就是在中断里面计数,来个中断计数加一,判断到自己想要的值就改变电平,这样做思路简单,但有一个坏处,就是有个0.14ms的误差无法消除(可能是我太菜,没找到解决方法),后来就想到用两个定时器做了,定时器0,用来改变周期,定时器1,用来改变占空比,当定时器0来一个中断时,PWM=1,并开启定时器1,定时器1来一个中断时,PWM=0,关闭定时器,至于为什么要关闭定时器1,是因为定时器1的初值比较小,可能在定时器0还没发生中断的时候,就发生几次中断了,所以会影响PWM输出,还有发生中断的时候,有一些时间,和运行的时候有些静态误差,所以在初值哪儿微调。
废话少说,直接上代码。
延时函数

#ifndef __DELAY_H
#define __DELAY_H
#include "reg51.h"
#define uchar unsigned char
#define uint unsigned int 
void delay_ms(uint i);

#endif

#include "delay.h"
void delay_ms(uint i)
{
	uchar n;
 	while(i--)
	for(n=0;n<120;n++)
	;

}

下面直接主函数了

#include "sys.h"				//自己写的一个头文件
#include "delay.h"

unsigned int tim0_I; //占空时间
unsigned int tim0_T;		 //周期
uchar Temp_TH0,Temp_TL0;
uchar Temp_TH1,Temp_TL1;

sbit PWM=P1^0;	//输出引脚
sbit key0=P3^2;
sbit key1=P3^3;
sbit key2=P2^0;
sbit key3=P2^1;
void INT_Init_KEY();
void key2_Init();
void key3_Init();
void TIM0_Init_PWM();	//初始化

//sbit LED=P1^0;
void main()
{
//	uchar i;

	tim0_I=600;
	tim0_T=1000;
	PWM=0;
	TIM0_Init_PWM();
	
	INT_Init_KEY();
	while(1)
	{
		key2_Init();
		key3_Init();
		delay_ms(10);	
	}
}


void TIM0_Init_PWM()		 //定时器0初始化
{
	TMOD=0x11;				//方式1:为16位定时/计数器
	TH0=(uint)(65535-tim0_T)/256;		//取低8位	//设置初始值10us
	TL0=(uint)(65535-tim0_T)%256;		 //取低8位
	TH1=(uint)(65535-tim0_I)/256;
	TL1=(uint)(65535-tim0_I)%256;
	TR1=1;
	TR0=1;
	ET1=1;		
	TR0=1;					 //打开定时器0
	ET0=1;					 //打开外部中断
	EA=1;					 //打开总中断

}

void tim0_Int_PWM()	interrupt 1 //设定周期
{
//	TR0=0;   				 //设置定时器初值期间,关闭定时器


  	TH0=(uint)(65535-tim0_T+28)/256;		 //定时器赋值
  	TL0=(uint)(65535-tim0_T+28)%256;		//加28是为了消除静态误差,还有中断反应时间,下面加30也一样
// 	TR0=1;
	PWM=1;
	TR1=1;
}
void tim1_Int_PWM()	interrupt 3 			//占空比
{
  				 
  	TH1=(uint)(65535-tim0_I+30)/256;		 //定时器赋值
  	TL1=(uint)(65535-tim0_I+30)%256;
	PWM=0;
	TR1=0;//需要把定时器1关了,这样它就不会一直跳,让它一个周期内只跳一次
}
void key2_Init()	 //周期加1
{
	if(key2==0)
	{
	delay_ms(100);
	if(key2==0)
	{
		tim0_T+=1000;
	}
	}
}
void key3_Init()	 //周期减1
{
	if(key3==0)
	{
	delay_ms(100);
	if(key3==0)
	{
		if(tim0_T>0)
			tim0_T-=1000;
	}
	}
}
void INT_Init_KEY()	   //外部中断初始化
{
	 EA=1;
	 EX0=1;
	 EX1=1;
	 IT0=1;
	 IT1=1;
	 PX0=1;
	 PX1=1;
}

void INT0_KEY0() interrupt 0	  //外部中断0 服务程序//占空时间加1
{
	delay_ms(10);
	if(key0==0)
	{
		if(tim0_I<tim0_T)
		tim0_I+=10;		
	}
	while(!key0) ;
}
void INT1_KEY1() interrupt 2	  //外部中断1 服务程序//占空时间减1
{
	delay_ms(10);
	if(key1==0)
	{	
		if(tim0_I>0)
		tim0_I-=10;
		
			
	}
	while(!key1) ;
}

我就一小白,不足之处,还请指出。

2010-10-26 10:58:00 fzxy002763 阅读数 2133
  • 巫妖王51单片机开发板配套视频课程

    本课程是巫妖王51单片机开发板的配套视频课程,本课程的目标是用少的时间带大家初级入门51单片机。配合巫妖王51单片机开发板,让大家花费少的时间少的钱就能轻松开启单片机学习之路。

    18609 人正在学习 去看看 朱有鹏

接上,继续介绍飞思卡尔HCS12系列单片机的PWM模块

(4)PWM预分频时钟寄存器(PWM Prescale Select Register)

PWMPRCLK为Clock A和B选择独立的预分频因子。

读:任何时刻  写:任何时刻

  Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
0 PCKB2 PCKB1 PCKB0 0 PCKA2 PCKA1 PCKA0
   
复位值 0 0 0 0 0 0 0 0

注意:PWMPRCLK寄存器的位可以在任何时刻写入,如果正在产生PWM信号时改变极性,在转换工程中可能截短或延长输出脉冲。

CLOCK A or B预分频因子的选择

PCKB2/PCKA2 PCKB1/PCKA1 PCKB0/PCKA0 CLOCK A or B的值
0 0 0 总线时钟
0 0 1 总线时钟2分频
0 1 0 总线时钟4分频
0 1 1 总线时钟8分频
1 0 0 总线时钟16分频
1 0 1 总线时钟32分频
1 1 0 总线时钟64分频
1 1 1 总线时钟128分频

(5)PWM分频时钟寄存器(PWM Scale x Register)

PWM分频时钟寄存器用于将CLOCK A or B进行分频,产生CLOCK SA or SB,通过将CLOCK A除以PWMSCLA寄存器中的值,再除以2,形成CLOCK SA.

CLOCK SA=(CLOCK A)/(X*PWMSCLA)

读:任何时刻  写;任何时刻(导致分频计数器装载新的比例因子值PWMSCLA)。

  Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
读/写 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
复位值 0 0 0 0 0 0 0 0

PWMSCLB的寄存器和A的完全相同。

注:若当PWMSCLA=500时,PWMSCLA默认值为256,此时CLOCK SA等于CLOCK A频率除以512.(即最大分频数为512)

(6)PWM极性寄存器(PWM Poarity Register)

PWMPOL是确定每个PWM通道波形开始的输出极性,如果极性选择位为1,周期开始时PWM通道输出高电平,当通道计数器等于占空比寄存器值时翻转为低电平;相反,如果极性选择位是0,周期开始时PWM通道输出低电平,当通道计数器数值等于占空比计数器时翻转为高电平。

读:任何时刻  写:任何时刻

  Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
读/写 PPOL7 PPOL6 PPOL5 PPOL4 PPOL3 PPOL2 PPOL1 PPOL0
复位值 0 0 0 0 0 0 0 0

注:PPOLx寄存器的位可以在任意时刻写入。如果正在产生PWM信号时改变极性,在转换过程中可能截短或延长输出脉冲。

(7)PWM居中对齐允许寄存器(PWM Center Align Enable Register)

PWMCAE包含8个控制位,用于控制相应的PWM通道输出波形为中心对齐输出或左对齐输出。如果CAEx=1,相应的PWM通道输出波形为中心对齐,如果CAEx=0,相应的PWM通道输出波形为左对齐。

读:任何时刻   写:任何时刻

  Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
读/写 CAE7 CAE6 CAE5 CAE4 CAE3 CAE2 CAE1 CAE0
复位值 0 0 0 0 0 0 0 0

注:仅当相应通道被禁止输出时,才可以设置该寄存器。

这里居中对齐寄存器很多情况下会与极性寄存器搞混。

左对齐格式输出时,8位计数器只作加法计数,当计数器计数到占空比寄存器中设置的数值时,PWM通道输出波形就会发生变化,然后再次读取占空比和周期寄存器中的数值以作为下一次参数。

居中对齐输出时,8位计数器即做加法计数也做减法计数,当计数器加法计数到占空比寄存器中设置的数值时,PWM通道输出波形就会发生改变,当计数器加法计数到周期寄存器中设置的数值时,计数器会从加法计数变为减法计数,当计数器再次减法计数到占空比寄存器中的数值时,PWM通道输出波形再次发生变化,当计数器中数值减到0时,计数器重新变为加法计数器,然后再次读取占空比和周期寄存器中的数值作为下一次参数。

总结为左对齐Period=PWMPERx,中心对齐Period=PWMPERx*2

(8)PWM控制寄存器(PWM Control Register)

PWMCTL控制寄存器,该寄存器用于PWM模块的各种控制,其中包括了4个级联控制位,用于将一对8位PWM通道级联成一个16位通道。

  Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
CON67 CON45 CON23 CON01 PSWAI PFRZ 0 0
   
复位值 0 0 0 0 0 0 0 0

 

 

读:任何时刻  写:任何时刻(导致分频计数器装载新的比例因子值PWMSCLA)

该控制寄存器设定通道的级联和两种工作模式:等待模式和冻结模式。

PSWAI:等待模式下PWM停止位。该位使能,通过禁止时钟输入到预分频器,可降低等待模式下的功耗。

1表示等待模式时,预分频器的时钟输入停止。

0表示等待模式时,允许预分频器的时钟输入。

PFRZ:冻结模式下PWM停止位。

1表示冻结模式时,预分频器的时钟输入停止。

0表示冻结模式时,允许PWM继续工作。

2017-05-31 15:27:16 Zach_z 阅读数 36190
  • 巫妖王51单片机开发板配套视频课程

    本课程是巫妖王51单片机开发板的配套视频课程,本课程的目标是用少的时间带大家初级入门51单片机。配合巫妖王51单片机开发板,让大家花费少的时间少的钱就能轻松开启单片机学习之路。

    18609 人正在学习 去看看 朱有鹏

一、PWM

Pulse Width Modulation脉冲宽度调制,简称PWM。

PWM(脉冲宽度调制)对模拟信号电平进行数字编码的方法,计算机只能输出0或5V的数字电压值而不能输出模拟电压,而我们如果想获得一个模拟电压值,则需通过使用高分辨率计数器,改变方波的占空比来对一个模拟信号的电平进行编码。

仍输出数字信号,因为满幅值的直流供电只有5V(1)和0V(0)两种。电压是以一种连接(1)或断开(0)的重复脉冲序列被夹到模拟负载上去的,连接即是直流供电输出,断开即是直流供电断开。通过对连接和断开时间的控制,只要带宽足够,可以输出任意不大于最大电压值的模拟电压。

     输出电压=(接通时间/脉冲时间)*最大电压值

这里写图片描述

二、51单片机的Timer

作者用的单片机是STC89C52,其内部有3个16位Timer,分别为T/C0,T/C1,T/C2,通过配置相关寄存器即可实现Timer的功能控制。

控制PWM需要用到定时器来生成不同占空比的波形,采用定时器中断的方式。

相关寄存器:

1.IE寄存器

名称 功能
0 EX0 外部中断0的中断允许位
1 ET0 Timer0的溢出中断允许位
2 EX1 外部中断1的中断允许位
3 ET1 Timer1的溢出中断允许位
4 ES 串行口中断允许位
5 ET2 Timer
6 - -
7 EA 中断允许总控制位

2. TCON寄存器

名称 功能
0 IT0 外部中断0的触发方式选择位。功能和IE1类似
1 IE0 外部中断0的中断请求标志位。功能和IE1类似
2 IT1 外部中断1的触发方式选择位。当IT1=1时,为下降沿触发方式,也就是从高到低的跳变会触发外部中断1。当IT1=0时,为低电平触发,也就是单片机检测到该引脚电平为低时,会触发外部中断1
3 IE1 外部中断1的中断请求标志位。当IE1=1的时候,表示外部中断1被触发,正在请求单片机处理中断事件。当单片机相应中断,处理中断事件时,该位由单片机自动清零
4 TR0 启动定时器/计数器0启动位,功能和TR1类似
5 TF0 定时器/计数器T0溢出中断请求标志位。功能和TF1类似.
6 TR1 启动定时器/计数器1启动位,TR=1启动计时,TR=0停止计时
7 TF1 定时器/计数器T1溢出中断请求标志位。当T1溢出时,该位自动置1。单片机响应相应中断时,系统自动清零TF1,也可以程序清零

3. TMOD寄存器

控制Timer0/1的工作方式

名称 功能
0 M0 工作方式选择位
1 M1 工作方式选择位
2 C/T 计数器模式和定时器模式选择位,C/T=1时,为计数器模式,C/T=0时,为定时器模式。C为counter的缩写,T为timer的缩写,这样方便理解
3 GATE T1(0)的启动源选择位,GATE=1时,用外部中断引脚INT1(INT0)上的高电平来启动T1(T0);GATE=0时,用TCON里的TR1(TR0)来启动T1(T0)。
4 M0 相似于0位
5 M1 相似于1位
6 C/T 相似于2位
7 GATE 相似于3位
M1 M0 工作方式
0 0 方式0,由TH1(TH0)的8位和TL1(TL0)的低5位组成一个13位定时器。
0 1 方式1,由TH1(TH0)的8位和TL1(TL0)的8位组成一个16位定时器。
1 0 方式2,TL1(TL0)溢出后,TH1(TH0)的数值自动填充到TL1(TL0)。
1 1 方式3,仅适用于T0,T0分成两个8位计数器,T1停止计数。

4. Timer0/1计数寄存器

TL0
TL1
TH0
TH1

当定时开启后,TL0(TL1)自动跟随机器周期加一。当TL0(TL1)满了后,自动清零同时向TH0(TH1)进一位,不需要手动操作.

而当TL0(TL1)和TH0(TH1)都满了以后,此时如果定时中断和总中断都已经打开,那么就会发生溢出中断,同时这两个寄存器清零

三、运用PWM完成呼吸灯

1. 硬件电路

这里写图片描述

2. 软件驱动

unsigned char PWM_COUNT; //计数
unsigned int HUXI_COUNT;    //占空比更新时间
unsigned char PWM_VLAUE;    //占空比比对值
bit direc_flag;             //占空比更新方向

void timer0_init()
{
    TMOD=0x02;          //模式设置,00010000,定时器0,工作于模式2(M1=1,M0=0)
    TH0=0x47;               //定时器溢出值设置,每隔200us发起一次中断。
    TL0=0X47;
    TR0=1;                  //定时器0开始计时
    ET0=1;                  //开定时器0中断
    EA=1;                       //开总中断
    PWM_COUNT =0;
}
void time0() interrupt 1
{   
    PWM_COUNT++;
    HUXI_COUNT++;
    if(PWM_COUNT == PWM_VLAUE)      //判断是否到了点亮LED的时候
        LED = 1;                    //点亮LED
    if(PWM_COUNT == 10)             //当前周期结束
    {
        LED = 0;                    //熄灭LED
        PWM_COUNT = 0;              //重新计时
    }
    if((HUXI_COUNT == 600) && (direc_flag == 0))
    {                               //占空比增加10%
        HUXI_COUNT = 0;
        PWM_VLAUE++;
        if(PWM_VLAUE == 9)          //占空比更改方向
            direc_flag = 1; 
    }
    if((HUXI_COUNT == 600) && (direc_flag == 1))
    {                               //占空比减少10%
        HUXI_COUNT = 0;
        PWM_VLAUE--;
        if(PWM_VLAUE == 1)          //占空比更改方向
            direc_flag = 0; 
    }   
}
void main()
{
    HUXI_COUNT = 0;
    PWM_COUNT = 0;
    PWM_VLAUE = 5;
    direc_flag = 0;
    LED = 1;            //默认LED熄灭   
    timer0_init();      //定时器0初始化
    while(1);
}

单片机 PWM输出 c

阅读数 1031

PIC单片机之PWM

阅读数 2213

PIC单片机的PWM功能主要是设置

博文 来自: huanghunshizhe2

STM32单片机PWM输出测试

博文 来自: qq_43667028
没有更多推荐了,返回首页