实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

历览千载书,时时见遗烈。这篇文章主要讲述实例5:寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分)相关的知识,希望能为你提供帮助。
按照总分总讲解故事的原则,前面学会了进行循迹小车的训练,包括原理、编程等基本工具的使用和逻辑框架。
本文将讲解深入一点的知识,进行本质的剖析。第一个内容是PWM是如何产生的?
stc8a8k的pwm是如何设置的?
这两个问题。
1、PWM的原理 https://www.basemu.com/what-is-pwm.html
1.1 PWM是什么?
PWM表示脉冲宽度调制,现在我们先将PWM理解为一种信号,它可以从微控制器或555定时器等数字集成电路中产生,它是一系列脉冲,这些脉冲将以方波的形式出现。也就是说,在任何给定的时间点,波型要么是高电平或者是低电平。为了便于理解,让我们假设有一个5V的PWM信号,高电平时PWM信号电压是5V,低电平时PWM信号是0V。信号保持在高电平的持续时间称为“接通时间”,信号保持在低电平的持续时间称为“断开时间”。对于PWM信号我们需要关注两个与之相关的重要参数,一个是PWM占空比,另一个是PWM信号的频率。
1.2 PWM的占空比
如前面所述,PWM信号在特定的时间内保持接通状态,然后在剩余的时间内保持断开状态。占空比是指在一个脉冲循环内,接通时间相对于总时间所占的比例。在一段连续工作时间内脉冲高电平时间与总时间的比值。如果信号总是处于高电平,它的占空比是百分之百;如果信号总是处于低电平,那么它的占空比是0%。计算占空比的公式如下所示:
占空比 =接通时间 / (接通时间 + 断开时间)

下图显示了一个具有50%占空比的PWM信号。正如您所看到的,PWM信号只在一半的时间内保持接通状态。PWM信号的占空比

实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

也就是说,通过控制从0%到100%的占空比,我们可以控制PWM信号的“接通时间”,从而控制信号的宽度。由于我们可以通过调节脉冲信号的宽度控制接通时间,所以将这种控制方式称为“脉冲宽度调制”。
1.4 PWM的频率
PWM信号的频率决定了PWM完成一个信号周期的速度。周期是指PWM信号完成一个接通和关闭的时间。计算频率的公式如下所示
频率 = 1 / 总持续时间
总持续时间 = 接通时间 + 断开时间
2、PWM的产生 产生的途径主要有4个,这个主要是针对增强版的单片机而言。
(1)延时
思路:比如在P10口产生PWM波形,可以这么实现:
大概代码。
P10=1;
delay(时间1);
P10=0;
delay(时间2);
这样,时间1+时间2=周期;
频率等于周期的倒数。
占空比=时间1/周期;
这个比较占用内部资源,不建议这么做,有一些必须这么做,可以使用。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

(2)定时器产生PWM。
这个普通的51单片机经常这么用。
网上有比较多资料说到这一点内容。具体不说,自己查资料。
缺点是,占用一个定时器资源。可以使用。
(3)内部PWM模块产生。
这个集中精力讲一下这个内容。
(4)PCA模块产生PWM,这个后面有时间再讲。
**内部PWM模块的产生。**下面主要讲这个。
3、stc8a8k的PWM原理和相关寄存器
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

3.1,要弄明白stc8a8k的PWM模块,需要解决几个问题。
【实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))】先看说明书的例子。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

有6个步骤。我们把这个步骤每个细节的寄存器了解清楚,就可以设置了。
(1)设置PWM时钟源;
(2)设置PWM周期;
(3)设置PWM的翻转点T1;
(4)设置PWM的翻转点T2;
(5)设置PWM的具体口允许输出PWM;
(6)设置PWM的大门允许输出。
有两个门进行使能。
比如进入一栋大楼,里面还有不同的房间。要打开大楼的大门,同时打开房间的小门,才能输出。所以需要第五,第六的允许输出。多重保险门。
第一个问题:
PWM的时钟源选择;
这个类比于心跳频率,这个决定之后,按照定时计数器,计算跳动的次数,就得到时间,就可以有周期等概念。
单片机内部的PWM模块,其实是利用计数器的功能。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

stc8a单片机的PWM模块是8路的独立的15位的PWM模块,这几个PWM的频率必须一致,占空比可以不一样。
可以输出8路的PWM;
是15位的PWM。15位的意思是,2的15次方,最大的计数数值是32765。当单片机从0—1---2–3--。。。–32765—0–1.。数到最大是32765的时候,归0,重新再数。每一次数数字的时间就是时钟心跳。我们可以根据需要设置。
图中的话,写得比较明白,PWM计数器可以设定1-32767作为计数周期,当计数到设定的计数周期(小于32767)的时候,从0重新计数。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

上面的图,是设定PWM的时钟源。就是计数的心跳,可以根据自己的需求进行设置。
本实验用的是:
1、分频后的时钟,所以SELT2=0,
2、分频的系数是12,所以PWM-PS=1011,
所以
PWMCKS=00001011=0x0b;
这个语句的作用是,设定PWM时钟源是晶振频率的12分之一。
就是fpwm=11.0592MHZ/12=11059200/12.
(因为下载的时候,选择了11.0592Mhz频率)
第二个问题:
计数的次数怎么决定;(周期的确定)
这个次数,就等价于周期了。
当设定了PWM时钟频率fpwm,计数假设为N,N的范围是(1-32767,因为是15位计数器,最大设定数值是32767),那么
假设时钟周期为时钟频率的倒数,设为tpwm,那么tpwm=1/fpwm,
PWM的周期Tsetpwm=N1/fpwm=Ntpwm,
PMW的频率是PWM周期的倒数,则是
fsetpwm=1/Tsetpwm=fpwm/N=11059200/12/N=921600/N(公式1)
根据公式1
假如外部设定了fsetpwm,那么反推出N,得到
N=921600/fsetpwm。
所以设定的周期
PWMC=921600/fsetpwm
下图中是将PWMC分为了高八位和低八位,我们直接写进去PWMC就可以了。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

第三个问题,占空比的决定;就是翻转点的设置。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

这里讲解第一个作为例子,PWM1T1H,PWM1T1L,
PWM1T2H,PWM2T2L。
有两个翻转点,PWM1T1和PWM1T2。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

当PWM计数器内部计数数值=PWM1T1,会反转一次变为低电平(需要设置初始电平是高电平);
当PWM计数器内部计数数值=PWM1T2,会翻转第二次,变为高电平。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

所以,假如我们想要设定的是占空比,设为zkb。
那么
T1=周期乘以占空比=Tzkb
由于是计数器,所以进行转换。
但是由于我们说的是计数的数值,所以需要进行转换。
等价于Nt1==N
zkb
就是
Nt1=Nzkb=921600zkb/fsetpwm。
Nt2=N,或者Nt2=0,因为当0计数到N的时候,会重新变为0。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

第四个问题,管脚切换的问题。
由于stc8a的单片机,有多个管脚通道可以输出PWM,所以要根据自己的硬件分配,设定PWM从哪个管脚输出PWM。
本开发板用P20,P21,P22,P23输出PWM,所以需要设置一下。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

用的是PWMiCR进行设置。
看一下这个寄存器。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

发现这个寄存器的作用比较多。我们把这个寄存器当做是一个门卫室,我们告诉里面的门卫一些口令,他就会按照我们的口令,进行相关的模式设置。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

设置这两位是00,就是从P2口输出PWM。
同时刚好这里的寄存器有个位,是控制初始电平是高电平,还是低电平的,我们设置时高电平,所以
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

这个位需要是1.
我们不需要设置中断,所以后面的都是0.
综上:
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

PWM0CR=11000000=0xc0,
这个指令的功能是。
允许输出PWM,
初始电平是高电平。
在P20输出PWM。
不允许中断(因为没用到PWM中断),
第五个问题,开启PWM的问题;
设定完之后,怎么开启PWM,怎么关闭PWM,当我们需要的时候开启,不需要的时候关闭。
PWMCR寄存器。
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

设置这个寄存器的B7=1,就可以开启了。
所以PWMCR=0x80=1000 0000,就是允许输出PWM了。
这里有个设置的技巧或者说需求。
有时候我们可以把这个寄存器当做是8个开关(B0----B7),我们只需要某一个开关打开或者关闭,其他开关保持原来的状态不变,怎么设置呢?
类似这个拨码开关,只需要关一个,其他保持不变,怎么办?
实例5(寄存器操作学习:stc8a8k单片机硬件PWM的原理和代码讲解(置1清0位操作和高8位低8位拆分))

文章图片

把这个问题,抽象为:置1或者清0操作。
置1:用或对应位1操作。
(A|B,有1为1,全0为0)
比如我们只想将B7置1,其他位不变,可以:
PWMCR |=0x80=1000 0000,
那么可将B7设置为1,其他位如果当初是1,或0,那么也是1,如果当初是0,或0,那么也是0,就保持不变。
清0:用与对应位0操作。
与:A& B,全1为1,有0为0.
PWMCR & =0x7f=0111 1111.
那么B7位与0,那么就必须等于0,实现清0;
其他位,如果初始态是0,与1,那么也是0。如果初始态是1,与1,结果是1,起到保持初始态的目的。
4、stc8a8的PWM的设置流程(初始化步骤+调整频率和挑调整占空比的步骤) 4.1初始化步骤: 1、打开设置开关:
2、设置对应管脚输出PWM;(管脚切换)
3、设置PWM时钟源;
4、设置PWM的初始电平为高电平和对应的PWM通道的允许输出PWM;
5、设置使能PWM的大门,允许输出PWM。
6、关闭设置开关。
P_SW2=0x80; //打开设置开关 //管脚切换+初始高电平,参考stc官方例程 PWM0CR = 0xc0; //在P20输出PWM0,初始高电平 PWM1CR = 0xc0; //在P21输出PWM1,初始高电平 PWM2CR = 0xc0; //在P22输出PWM2,初始高电平 PWM3CR = 0xc0; //在P23输出PWM3,初始高电平 //设置PWM时钟源系统时钟/12=11.0592mhz/12; PWMCKS=0X0b; //PWM配置寄存器 PWMCFG = 0x00; PWMCR |=0x80; //使能PWM模块 P_SW2 =0x00;

4.2设置周期、设置占空比; 这个在具体调整的函数里面实现。
//****************************************** void HPWM_Set(int PWMchannel, unsigned int f,float zkb) { unsigned intCycleTime; P_SW2=0x80; //打开设置开关 //根据频率,计算周期=频率的倒数,设置计数周期 //921600=11.0592Mhz/12=11059200/12,兆,等于10的6次方。 //用到强制类型转换,将计算的小数强制转换为无符号整型, //因为计数器只能是整数,而且是0-32767之间。 CycleTime=(unsigned int)(921600/f); //根据频率算得周期 PWMC=CycleTime; //设置PWM周期,放到对应的寄存器中。 //看设置的那个通道的占空比; switch(PWMchannel) { case 0://P20通道,PWM0的占空比,翻转点设置; PWM0T1 =zkb*CycleTime; //N*zkb=Nt1 PWM0T2 = 0; //当计数到CYCLE的时候,会归0 break; case 1://P21通道,PWM1的占空比,翻转点设置; PWM1T1 =zkb*CycleTime; // PWM1T2 = 0; //当计数到CYCLE的时候,会归0 break; case 2: //P22通道,PWM2的占空比,翻转点设置; PWM2T1 =zkb*CycleTime; // PWM2T2 =0; //当计数到CYCLE的时候,会归0 break; case 3: PWM3T1 =zkb*CycleTime; PWM3T2 = 0; //当计数到CYCLE的时候,会归0 break; default: break; // } PWMCR |= 0x80; //使能PWM模块 P_SW2=0x00; //关闭设置开关 }

结论:
通过上面讲解,得到设置寄存器的步骤;
(1)了解具体的对象的概念,什么是PWM?
(2)学习芯片例程的设置流程。看芯片手册对应目录;
(3)抽象问题,设置对应的参数。
(4)关于寄存器:
—控制寄存器相当于门卫房间。
接收的是控制指令,需要明白什么指令什么作用,对上暗号,它就听你话,按照你的想法干活;
需要熟悉置1,清0的位操作。
—数据寄存器,就是一个放数据的房间。
一般分为两个房间,
一个房间放数据的高八位,
一个房间放低八位的数据,
所以有一些场合,需要把数据拆成高八位的数据和低八位的数据,放到对应的房间。
怎么拆分?
用求余数或者求模运算就可以了。
比如有一个数int a=3000;
高8位假如是ahigh,那ahigh=a/256;
低八位alow=a%256;
将ahigh放到高8位的房间,alow放到低8位的房间。

    推荐阅读