基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用

news2025/1/18 6:19:22

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用

  • STC12C5A60S2系列1T 8051单片机管脚图
  • STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置
  • STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍
  • STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的结构
  • STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的各种不同工作模式介绍
  • 基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的特殊功能寄存器列表
    • 基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)模块用到的特殊功能寄存器
      • PCA辅助寄存器AUXR1
      • PCA工作模式寄存器CMOD
      • PCA工作模式寄存器CCON
      • PCA比较/捕获寄存器CCAPM0和CCAPM1
      • PCA的16位定时器/计数器 —— 高八位CH和低八位CL
      • PCA捕获/比较寄存器高八位CCAPnH和低八位CCAPnL
      • PCA的PWM寄存器PCA_PWM0和PCA_PWM1
      • 利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块0从P1.3引脚输出频率为200Hz且占空比为40%的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序
      • 利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块0从P1.3引脚输出频率为200Hz且占空比可调的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序![在这里插入图片描述](https://img-blog.csdnimg.cn/3d3287492e2340959a5c40d59a81b247.jpg)![在这里插入图片描述](https://img-blog.csdnimg.cn/a860de5af3594e38aae903d822a3dc94.jpg)![在这里插入图片描述](https://img-blog.csdnimg.cn/470345c725034aad991d0c8c471f79f9.jpg)![在这里插入图片描述](https://img-blog.csdnimg.cn/e7dccf59143c41eb9aa01d538836329f.jpg)
      • 利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机定时器0的16位定时器模式1定时计数溢出作为可编程计数阵列CCP/PCA/PWM模块0的时钟源输入来从P1.3引脚输出频率为1KHz且占空比可调的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序

STC12C5A60S2系列1T 8051单片机管脚图

在这里插入图片描述在这里插入图片描述

STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置

在这里插入图片描述

STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍

在这里插入图片描述在这里插入图片描述

STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的结构

在这里插入图片描述在这里插入图片描述

STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的各种不同工作模式介绍

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的特殊功能寄存器列表

在这里插入图片描述

基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)模块用到的特殊功能寄存器

PCA辅助寄存器AUXR1

在这里插入图片描述
作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的单片机引脚

PCA工作模式寄存器CMOD

在这里插入图片描述
作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块以下功能
(1)、空闲情况下是否停止CCP/PCA/PWM模块计数
(2)、CCP/PCA/PWM模块计数脉冲时钟源选择 (3)、CCP/PCA/PWM模块计数溢出中断使能

PCA工作模式寄存器CCON

在这里插入图片描述
作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块以下功能
(1)、CCP/PCA/PWM模块计数溢出标志位
(2)、CCP/PCA/PWM模块运行
(3)、CCP/PCA/PWM模块0中断标志位
(4)、CCP/PCA/PWM模块1中断标志位

PCA比较/捕获寄存器CCAPM0和CCAPM1

在这里插入图片描述在这里插入图片描述
作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块以下功能
(1)、CCP/PCA/PWM模块0允许比较器功能控制
(2)、CCP/PCA/PWM模块0上升沿捕获控制
(3)、CCP/PCA/PWM模块0下降沿捕获控制
(4)、CCP/PCA/PWM模块0匹配工作模式寄存器CCON中断标志位控制
(5)、CCP/PCA/PWM模块0匹配CCPn寄存器引脚电平翻转控制
(6)、CCP/PCA/PWM模块0脉冲宽度调制模式
(7)、CCP/PCA/PWM模块0使能工作模式寄存器CCON中断标志位控制
(8)、CCP/PCA/PWM模块1允许比较器功能控制
(9)、CCP/PCA/PWM模块1上升沿捕获控制
(10)、CCP/PCA/PWM模块1下降沿捕获控制
(11)、CCP/PCA/PWM模块1匹配工作模式寄存器CCON中断标志位控制
(12)、CCP/PCA/PWM模块1匹配CCPn寄存器引脚电平翻转控制
(13)、CCP/PCA/PWM模块1脉冲宽度调制模式
(14)、CCP/PCA/PWM模块1使能工作模式寄存器CCON中断标志位控制

PCA的16位定时器/计数器 —— 高八位CH和低八位CL

在这里插入图片描述
作用:作为CCP/PCA/PWM模块0或CCP/PCA/PWM模块1的计数器进行脉冲计数

PCA捕获/比较寄存器高八位CCAPnH和低八位CCAPnL

在这里插入图片描述
作用:作为捕获或比较时 用于CCP/PCA/PWM模块0或CCP/PCA/PWM模块1的计数器进行脉冲计数 作为脉冲宽度调制时 用于CCP/PCA/PWM模块0或CCP/PCA/PWM模块1的高八位CCAPnH脉冲计数重载给低八位CCAPnL进行脉冲计数控制脉冲宽度调制

PCA的PWM寄存器PCA_PWM0和PCA_PWM1

在这里插入图片描述
作用:组成CCP/PCA/PWM模块0或CCP/PCA/PWM模块1的PWM寄存器内部累计计数的9位数据

利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块0从P1.3引脚输出频率为200Hz且占空比为40%的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

#include <STC12C5A60S2.h>
void PortModeSet();//端口模式设置函数
void PcaInit();//CCP/PCA/PWM模块初始化函数
void Timer0Init();//定时0初始化函数
 void main()
{
  PortModeSet();//端口模式设置函数
  PcaInit();//CCP/PCA/PWM模块初始化函数
  Timer0Init();//定时0初始化函数
  while(1);
 }
 void PortModeSet()//端口模式设置函数
{  
  P0M1 = 0x00;
  P0M0 = 0x00;
  P1M1 = 0x00;
  P1M0 = 0x00;
  P2M1 = 0x00;
  P2M0 = 0x00;
  P3M1 = 0x00;
  P3M0 = 0x00;
  P4M1 = 0x00;
  P4M0 = 0x00;
 }
 void PcaInit()//CCP/PCA/PWM模块初始化函数
{
  CMOD = 0x04 ;//CCP/PCA/PWM模块空闲模式下CCP/PCA/PWM模块计数器继续工作 选定时器T0溢出脉冲作为CCP/PCA/PWM模块时钟源 禁止CCP/PCA/PWM模块溢出中断使能
  CCON = 0x00;//CCP/PCA/PWM模块计数溢出标志位清0 运行位清0 中断标志位清0
  CCAPM0 = 0x42;//CCP/PCA/PWM模块0允许比较器功能控制 不允许边沿捕获控制 不匹配工作模式寄存器CCON中断标志位控制 不匹配CCPn寄存器引脚电平翻转控制 输出脉冲宽度调制模式 不使能工作模式寄存器CCON中断标志位控制
  CH = 0x00;//CCP/PCA/PWM模块16位计数器高八位计数寄存器脉冲计数清0
  CL = 0x00;//CCP/PCA/PWM模块16位计数器低八位计数寄存器脉冲计数清0
  CCAP0H = 0x00;//同下
  CCAP0L = 0x00;//CCP/PCA/PWM模块
  CR = 1;//启动CCP/PCA/PWM模块16计数器
 }
 void Timer0Init()//定时器0初始化函数
{
  AUXR = 0x80;//将定时器/计数器设置为1T模式 不用分频 
  TMOD = 0x02;//选定时器/计数器为定时器0 工作模式为模式2的8位自动重装计数 即溢出时将TH0存放的脉冲计数自动装入TL0
  TH0 = 0x16;//由于选定时器/计数器为1T模式不用分频定时器0 工作模式为模式2的8位自动重装计数 因此先根据PWM频率=CCP/PCA/PWM模块时钟源频率/256求出CCP/PCA/PWM模块时钟源频率 即200Hz=CCP/PCA/PWM模块时钟源频率/256 求CCP/PCA/PWM模块时钟源频率=51200Hz 再根据定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)求出定时器初值(定时计数初值) 即定时器初值(定时计数初值)=2^8-(12MHz/1/51200Hz)=256-(12000000Hz/51200Hz)=256-234=22=0x16
  TL0 = 0x16;//同上
  EA = 1;//打开定时器中断总开关
  TR0 = 1;//启动定时器0
 } 

利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块0从P1.3引脚输出频率为200Hz且占空比可调的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

#include <STC12C5A60S2.h>
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
#define KeyPressDeshakeTime 10//自定义按键按下消抖时间为10ms
#define KeyLongPressDelayTime 500//自定义按键长按延时时间为500ms
#define KeyLongPressIntervalChangeTime 25//自定义按键长按间隔变化时间为25ms
uchar AddKeyLockFlag;//声明增加按键锁定标志位变量
uchar DecKeyLockFlag;//声明减少按键锁定标志位变量
uchar KeyNumber = 0;//定义按键键值为0
uchar AddKeyLongPressAddIntervalTime;//声明增加按键长按连增间隔时间变量
uchar DecKeyLongPressDecIntervalTime;//声明减少按键长按连减间隔时间变量
uint AddKeyPressDelayTime;//声明增加按键按下延时时间变量
uint DecKeyPressDelayTime;//声明减少按键按下延时时间变量
sbit AddKey = P2^0;//位定义增加按键为单片机P2.0引脚
sbit DecKey = P2^1;//位定义减少按键为单片机P2.1引脚
uchar PwmValue;//声明脉宽调制值变量
void PortModeSet();//端口模式设置函数
void PcaInit();//CCP/PCA/PWM模块初始化函数
void Timer0Init();//定时器0初始化函数
void Timer1Init();//定时器1初始化函数
void PwmDutyCycleSet();//脉冲宽度占空比设置函数
 void main()//主函数
{
  PortModeSet();//端口模式设置函数
  PcaInit();//CCP/PCA/PWM模块初始化函数
  Timer0Init();//定时器0初始化函数
  Timer1Init();//定时器1初始化函数
  while(1)
 {
   PwmDutyCycleSet();//脉冲宽度占空比设置函数
  }
 }
 void PortModeSet()//端口模式设置函数
{  
  P0M1 = 0x00;
  P0M0 = 0x00;
  P1M1 = 0x00;
  P1M0 = 0x00;
  P2M1 = 0x00;
  P2M0 = 0x00;
  P3M1 = 0x00;
  P3M0 = 0x00;
  P4M1 = 0x00;
  P4M0 = 0x00;
 }
 void PcaInit()//CCP/PCA/PWM模块初始化函数
{
  CMOD = 0x84 ;//CCP/PCA/PWM模块空闲模式下CCP/PCA/PWM模块计数器停止工作 选定时器T0溢出脉冲作为CCP/PCA/PWM模块时钟源 禁止CCP/PCA/PWM模块溢出中断使能
  CCON = 0x00;//CCP/PCA/PWM模块计数溢出标志位清0 运行位清0 中断标志位清0
  CCAPM0 = 0x42;//CCP/PCA/PWM模块0允许比较器功能控制 不允许边沿捕获控制 不匹配工作模式寄存器CCON中断标志位控制 不匹配CCPn寄存器引脚电平翻转控制 输出脉冲宽度调制模式 不使能工作模式寄存器CCON中断标志位控制
  CH = 0x00;//CCP/PCA/PWM模块16位计数器高八位计数寄存器脉冲计数清0
  CL = 0x00;//CCP/PCA/PWM模块16位计数器低八位计数寄存器脉冲计数清0
  CCAP0H = 0x00;//同下
  CCAP0L = 0x00;//CCP/PCA/PWM模块
  CR = 1;//启动CCP/PCA/PWM模块16计数器
 }   
 void Timer0Init()//定时器0初始化函数
{
  AUXR = 0x80;//将定时器/计数器设置为1T模式 不用分频 
  TMOD = 0x02;//选定时器/计数器为定时器0 工作模式为模式2的8位自动重装计数 即溢出时将TH0存放的脉冲计数自动装入TL0
  TH0 = 0x16;//由于选定时器/计数器为1T模式不用分频定时器0 工作模式为模式2的8位自动重装计数 因此先根据PWM频率=CCP/PCA/PWM模块时钟源频率/256求出CCP/PCA/PWM模块时钟源频率 即200Hz=CCP/PCA/PWM模块时钟源频率/256 求CCP/PCA/PWM模块时钟源频率=51200Hz 再根据定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)求出定时器初值(定时计数初值) 即定时器初值(定时计数初值)=2^8-(12MHz/1/51200Hz)=256-(12000000Hz/51200Hz)=256-234=22=0x16
  TL0 = 0x16;//同上
  EA = 1;//打开定时器中断总开关
  TR0 = 1;//启动定时器0
 }
 /*****关于通过特殊功能寄存器AUXR设定定时器/计数器模式为1T或12T模式不需分频或需12分频8051系列单片机定时器初值(定时计数初值)计算的知识点*****/
  /****
  时钟周期(又称振荡周期):单片机晶振频率的倒数 例:单片机晶振频率12MHz 则时钟周期=[1/(12*10^6)Hz]s=0.000000083s=0.000083ms=0.083us
  机器周期:单片机执行一条指令过程中需要完成一个基本操作(如:取指、译码、执行等基本操作)所需的时间 8051系列单片机的一个机器周期由6个S周期(状态周期)组成 一个时钟周期定义为一个节拍(用P表示) 二个节拍定义为一个状态周期(用S表示) 那么8051单片机的机器周期由6个状态周期组成 也就是说一个机器周期=6个状态周期=12个时钟周期=[12x[1/(12*10^6)Hz]s]s=0.000001s=0.001ms=1us
  指令周期:单片机取出一条指令且执行完这条指令所需的时间
  以上三者间的关系:指令周期>机器周期>时钟周期
  一、通过特殊功能寄存器AUXR设定定时器/计数器模式为12T模式需12分频8051系列单片机定时器初值(定时计数初值)计算步骤如下(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
  0、计算nT单片机机器周期T公式:T=n*(1/晶振频率)=几us
  1、一个机器周期=12个时钟周期=12乘以单片机晶振频率的倒数=12*[1/(12*10^6)Hz]s=0.000001s=0.001ms=1us
  2、定时时间=定时计数*一个机器周期 1ms=定时计数*1us 定时计数=1ms/1us=1000us/1us=1000次
  3、定时器初值(定时计数初值)=2^n-定时计数 n为几位定时器 此处n=16 则定时器初值(定时计数初值)=2^16-1000=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256 低八位放TL0=0x18或(65536-64536)%256
  二、以下是通过特殊功能寄存器AUXR设定定时器/计数器模式为1T或12T模式不需分频或需12分频8051系列单片机定时器初值(定时计数初值)计算步骤如下(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
  1、综合公式:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率) n为几位定时器 该公式常用于脉冲宽度调制中运算 例如:利用8051系列单片机晶振频率为12MHz的定时器0的16位定时模式1来产生1KHz方波脉冲 由此可知:定时时间=1/定时频率=1/1000Hz=0.001s=1ms=1000us 进而可得:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)=2^16-(12MHz/12/1KHz)=2^16-(12*10^6)Hz/12/1000Hz)=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256或Value >> 8 低八位放TL0=0x18或(65536-64536)%256或=Value 
  2、TH0 = Value >> 8;TL0 = Value;该两句代码解释如下:
  (1)、TH0 = Value >> 8相当于TH0 = (65536-10000)/256=55536/256=216.9375 分析:65536-10000=55536转化成二进制为11011000 11110000 55536/256=216.9375转化成二进制为11011000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000右移8位就可以得到55536/256=216.9375的二进制数11011000
  (2)、TL0 = Value相当于TL0 = (65536-10000)%256=55536%256=240 分析:65536-10000=55536转化成二进制为11011000 11110000 55536%256=240转化成二进制为11110000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000取低8位就可以得到55536%256=240的二进制数11110000
  ****/
 void Timer1Init(void)//定时器1定时2ms初始化函数 晶振为12MHz
{
  AUXR = 0x00;//将定时器/计数器设置为12T模式 用12分频 
  TMOD &= 0x0f;//设定定时器/计数器工作模式清0
  TMOD |= 0x10;//设定定时器/计数器为定时器 工作模式为16位定时器1模式1
  TH1 = 0xf8;//设定定时器1计数高8位初值
  TL1 = 0x30;//设定定时器1计数低8位初值
  TF1 = 0;//定时器1溢出中断标志位清0
  ET1 = 1;//打开定时器1中断开关
  EA = 1;//打开定时器中断总开关
  TR1 = 1//打开定时器1开关
 } 
 void Timer1(void) interrupt 3//定时器1定时2ms中断函数 晶振为12MHz
{
  TR1 = 0;//关闭定时器1
  KeyScan();//按键扫描函数
  TH1 = 0xf8;//设定定时器1计数高8位初值
  TL1 = 0x30;//设定定时器1计数低8位初值
  TR1 = 1;//打开定时器1
 }
 void KeyScan(void)//按键扫描函数 该函数放在定时器定时2ms的中断函数中扫描
{
  if(AddKey)//如果增加按键没按下或弹起
 {
   AddKeyLockFlag = 0;//增加按键锁定标志位清0
   AddKeyPressDelayTime = 0;//增加按键按下延时时间清0
  }   
  else if(!AddKeyLockFlag)//如果增加按键锁定标志位置1 即增加按键按下
 {
   AddKeyPressDelayTime++;//增加按键按下延时时间自加
   if(AddKeyPressDelayTime > KeyPressDeshakeTime)//如果增加按键按下延时时间大于按键按下消抖时间
  {
    AddKeyPressDelayTime = 0;//增加按键按下延时时间清0
    KeyNumber = 1;//按键键值置1 此处是单击增加 可赋给swicth()语句中的变量来对数值单击增加
    AddKeyLockFlag = 1;//增加按键锁定标志位置1
   }
  }
  else if(AddKeyPressDelayTime < KeyLongPressDelayTime)//如果增加按键按下延时时间小于按键长按延时时间
 {
   AddKeyPressDelayTime++;//增加按键按下延时时间自加
  }
  else//如果增加按键按下延时时间大于按键长按延时时间
 {
   AddKeyLongPressAddIntervalTime++;//增加按键长按连增间隔时间自加
   if(AddKeyLongPressAddIntervalTime > KeyLongPressIntervalChangeTime)//如果增加按键长按连增间隔时间大于按键长按间隔变化时间
  {
     AddKeyLongPressAddIntervalTime = 0;//增加按键长按连增间隔时间清0
     KeyNumber = 1;//按键键值置1 此处是连击增加 可赋给swicth()语句中的变量来对数值连击增加
   }
  }   
  if(DecKey)//如果减少按键没按下或弹起
 {
   DecKeyLockFlag = 0;//减少按键锁定标志位清0
   DecKeyPressDelayTime = 0;//减少按键按下延时时间清0
  }   
  else if(!DecKeyLockFlag)//如果减少按键锁定标志位置1 即减少按键按下
 {
   DecKeyPressDelayTime++;//减少按键按下延时时间自加
   if(DecKeyPressDelayTime > KeyPressDeshakeTime)//如果减少按键按下延时时间大于按键按下消抖时间
  {
    DecKeyPressDelayTime = 0;//减少按键按下延时时间清0
    KeyNumber = 2;//按键键值置2 此处是单击减少 可赋给swicth()语句中的变量来对数值单击减少
    DecKeyLockFlag = 1;//减少按键锁定标志位置1
   }
  }
  else if(DecKeyPressDelayTime < KeyLongPressDelayTime)//如果减少按键按下延时时间小于按键长按延时时间
 {
   DecKeyPressDelayTime++;//减少按键按下延时时间自加
  }
  else//如果减少按键按下延时时间大于按键长按延时时间
 {
   DecKeyLongPressDecIntervalTime++;//减少按键长按连减间隔时间自加
   if(DecKeyLongPressDecIntervalTime > KeyLongPressIntervalChangeTime)//如果减少按键长按连减间隔时间大于按键长按间隔变化时间
  {
    DecKeyLongPressDecIntervalTime = 0;//减少按键长按连减间隔时间清0
    KeyNumber = 2;//按键键值置2 此处是连击减少 可赋给swicth()语句中的变量来对数值连击减少
    }
   }
 }
 void PwmDutyCycleSet()//脉冲宽度占空比设置函数
{
  switch(KeyNumber)//按键类型筛选位
 {
   case 1 ://增加按键单击、长按触发位
           PwmValue++;//脉冲宽度值自加
           if(PwmValue > 255)//如果脉冲宽度值大于255
          {
            PwmValue = 255;//脉冲宽度值等于255
           }
           CCAP0H = CCAP0L = PwmValue;//脉冲宽度值赋给CCP/PCA/PWM模块0高低八位捕获/比较寄存器
           KeyNumber = 0;//按键键值清0
           break;//跳出
   case 2 ://减少按键单击、长按触发位
           PwmValue--;//脉冲宽度值自减
           if(PwmValue < 0)//如果脉冲宽度值小于
          {
            PwmValue = 0;//脉冲宽度值清0
           }
           CCAP0H = CCAP0L = PwmValue;//脉冲宽度值赋给CCP/PCA/PWM模块0高低八位捕获/比较寄存器
           KeyNumber = 0;//按键键值清0
           break;//跳出
   default:break;//跳出
  }
 }

利用晶振频率为12MHz的STC12C5A60S2系列1T 8051单片机定时器0的16位定时器模式1定时计数溢出作为可编程计数阵列CCP/PCA/PWM模块0的时钟源输入来从P1.3引脚输出频率为1KHz且占空比可调的矩形波 可根据以下CCP/PCA/PWM模块的脉冲宽度调制模式来编写程序

#include <STC12C5A60S2.h>
#define uchar unsigned char//自定义无符号字符型为uchar
#define uint unsigned int//自定义无符号整数型为uint
#define KeyPressDeshakeTime 10//自定义按键按下消抖时间为10ms
#define KeyLongPressDelayTime 500//自定义按键长按延时时间为500ms
#define KeyLongPressIntervalChangeTime 25//自定义按键长按间隔变化时间为25ms
uchar AddKeyLockFlag;//声明增加按键锁定标志位变量
uchar DecKeyLockFlag;//声明减少按键锁定标志位变量
uchar KeyNumber = 0;//定义按键键值为0
uchar AddKeyLongPressAddIntervalTime;//声明增加按键长按连增间隔时间变量
uchar DecKeyLongPressDecIntervalTime;//声明减少按键长按连减间隔时间变量
uint AddKeyPressDelayTime;//声明增加按键按下延时时间变量
uint DecKeyPressDelayTime;//声明减少按键按下延时时间变量
sbit AddKey = P2^0;//位定义增加按键为单片机P2.0引脚
sbit DecKey = P2^1;//位定义减少按键为单片机P2.1引脚
uchar PwmValue;//声明脉宽调制值变量
void PortModeSet();//端口模式设置函数
void PcaInit();//CCP/PCA/PWM模块初始化函数
void Timer0Init();//定时器0初始化函数
void Timer1Init();//定时器1初始化函数
void PwmDutyCycleSet();//脉冲宽度占空比设置函数
 void main()//主函数
{
  PortModeSet();//端口模式设置函数
  PcaInit();//CCP/PCA/PWM模块初始化函数
  Timer0Init();//定时器0初始化函数
  Timer1Init();//定时器1初始化函数
  while(1)
 {
   PwmDutyCycleSet();//脉冲宽度占空比设置函数
  }
 }
 void PortModeSet()//端口模式设置函数
{  
  P0M1 = 0x00;
  P0M0 = 0x00;
  P1M1 = 0x00;
  P1M0 = 0x00;
  P2M1 = 0x00;
  P2M0 = 0x00;
  P3M1 = 0x00;
  P3M0 = 0x00;
  P4M1 = 0x00;
  P4M0 = 0x00;
 }
 void PcaInit()//CCP/PCA/PWM模块初始化函数
{
  CMOD = 0x84 ;//CCP/PCA/PWM模块空闲模式下CCP/PCA/PWM模块计数器停止工作 选定时器T0溢出脉冲作为CCP/PCA/PWM模块时钟源 禁止CCP/PCA/PWM模块溢出中断使能
  CCON = 0x00;//CCP/PCA/PWM模块计数溢出标志位清0 运行位清0 中断标志位清0
  CCAPM0 = 0x42;//CCP/PCA/PWM模块0允许比较器功能控制 不允许边沿捕获控制 不匹配工作模式寄存器CCON中断标志位控制 不匹配CCPn寄存器引脚电平翻转控制 输出脉冲宽度调制模式 不使能工作模式寄存器CCON中断标志位控制
  CH = 0x00;//CCP/PCA/PWM模块16位计数器高八位计数寄存器脉冲计数清0
  CL = 0x00;//CCP/PCA/PWM模块16位计数器低八位计数寄存器脉冲计数清0
  CCAP0H = 0x00;//同下
  CCAP0L = 0x00;//CCP/PCA/PWM模块
  CR = 1;//启动CCP/PCA/PWM模块16计数器
 }
 /*****关于通过特殊功能寄存器AUXR设定定时器/计数器模式为1T或12T模式不需分频或需12分频8051系列单片机定时器初值(定时计数初值)计算的知识点*****/
  /****
  时钟周期(又称振荡周期):单片机晶振频率的倒数 例:单片机晶振频率12MHz 则时钟周期=[1/(12*10^6)Hz]s=0.000000083s=0.000083ms=0.083us
  机器周期:单片机执行一条指令过程中需要完成一个基本操作(如:取指、译码、执行等基本操作)所需的时间 8051系列单片机的一个机器周期由6个S周期(状态周期)组成 一个时钟周期定义为一个节拍(用P表示) 二个节拍定义为一个状态周期(用S表示) 那么8051单片机的机器周期由6个状态周期组成 也就是说一个机器周期=6个状态周期=12个时钟周期=[12x[1/(12*10^6)Hz]s]s=0.000001s=0.001ms=1us
  指令周期:单片机取出一条指令且执行完这条指令所需的时间
  以上三者间的关系:指令周期>机器周期>时钟周期
  一、以下是通过特殊功能寄存器AUXR设定定时器/计数器模式为12T模式需12分频8051系列单片机定时器初值(定时计数初值)计算步骤如下(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
  0、计算nT单片机机器周期T公式:T=n*(1/晶振频率)=几us
  1、一个机器周期=12个时钟周期=12乘以单片机晶振频率的倒数=12*[1/(12*10^6)Hz]s=0.000001s=0.001ms=1us
  2、定时时间=定时计数*一个机器周期 1ms=定时计数*1us 定时计数=1ms/1us=1000us/1us=1000次
  3、定时器初值(定时计数初值)=2^n-定时计数 n为几位定时器 此处n=16 则定时器初值(定时计数初值)=2^16-1000=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256 低八位放TL0=0x18或(65536-64536)%256
  二、以下是通过特殊功能寄存器AUXR设定定时器/计数器模式为1T或12T模式不需分频或需12分频8051系列单片机定时器初值(定时计数初值)计算步骤如下(以单片机晶振频率为12MHz 定时器0工作模式为16位定时模式1 需要定时1ms来计算):
  1、综合公式:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率) n为几位定时器 该公式常用于脉冲宽度调制中运算 例如:利用8051系列单片机晶振频率为12MHz的定时器0的16位定时模式1来产生1KHz方波脉冲 由此可知:定时时间=1/定时频率=1/1000Hz=0.001s=1ms=1000us 进而可得:定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)=2^16-(12MHz/12/1KHz)=2^16-(12*10^6)Hz/12/1000Hz)=65536-1000=64536 把64536转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xfc或(65536-64536)/256或Value >> 8 低八位放TL0=0x18或(65536-64536)%256或=Value 
  2、TH0 = Value >> 8;TL0 = Value;该两句代码解释如下:
  (1)、TH0 = Value >> 8相当于TH0 = (65536-10000)/256=55536/256=216.9375 分析:65536-10000=55536转化成二进制为11011000 11110000 55536/256=216.9375转化成二进制为11011000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000右移8位就可以得到55536/256=216.9375的二进制数11011000
  (2)、TL0 = Value相当于TL0 = (65536-10000)%256=55536%256=240 分析:65536-10000=55536转化成二进制为11011000 11110000 55536%256=240转化成二进制为11110000 由此可看出Value为(65536-10000)=55536的二进制数11011000 11110000取低8位就可以得到55536%256=240的二进制数11110000
  ****/
 void Timer0Init()//定时器0定时1ms初始化函数
{
  AUXR = 0x80;//将定时器/计数器设置为1T模式 不用用分频 
  TMOD = 0x01;//选定时器/计数器为定时器0 工作模式为16定时器模式1 
  TH0 = 0xff;//由于选定时器/计数器为1T模式 不用分频定时器0 因此先根据PWM频率=CCP/PCA/PWM模块时钟源频率/256求出CCP/PCA/PWM模块时钟源频率 即1KHz=1000Hz=CCP/PCA/PWM模块时钟源频率/256 求CCP/PCA/PWM模块时钟源频率=256000Hz 再根据定时器初值(定时计数初值)=2^n-(晶振频率/几分频/定时频率)求出定时器初值(定时计数初值) 即定时器初值(定时计数初值)=2^16-(12MHz/1/256000Hz)=65536-(12000000Hz/1/256000Hz)=65536-(12000000Hz/256000Hz)=65536-47=65489 把65489转化成十六进制 拆开成高八位和低八位 高八位放TH0=0xff或(65536-65489)/256或Value >> 8 低八位放TL0=0xd1或(65536-65489)%256或=Value 
  TL0 = 0xd1;//同上
  TF0 = 0;//定时器0溢出中断标志位清0
  ET0 = 1;//打开定时器0中断开关
  EA = 1;//打开定时器中断总开关
  TR0 = 1;//启动定时器0
 }
 void Timer0(void) interrupt 1//定时器0定时1ms中断函数 晶振为12MHz
{
  TR0 = 0;//关闭定时器0
  KeyScan();//按键扫描函数
  TH0 = 0xff;//设定定时器0计数高8位初值
  TL0 = 0xd1;//设定定时器0计数低8位初值
  TR0 = 1;//打开定时器0
 }
 void Timer1Init(void)//定时器1定时2ms初始化函数 晶振为12MHz
{
  AUXR = 0x00;//将定时器/计数器设置为12T模式 用12分频 
  TMOD &= 0x0f;//设定定时器/计数器工作模式清0
  TMOD |= 0x10;//设定定时器/计数器为定时器 工作模式为16位定时器1模式1
  TH1 = 0xf8;//设定定时器1计数高8位初值
  TL1 = 0x30;//设定定时器1计数低8位初值
  TF1 = 0;//定时器1溢出中断标志位清0
  ET1 = 1;//打开定时器1中断开关
  EA = 1;//打开定时器中断总开关
  TR1 = 1//打开定时器1开关
 } 
 void Timer1(void) interrupt 3//定时器1定时2ms中断函数 晶振为12MHz
{
  TR1 = 0;//关闭定时器1
  KeyScan();//按键扫描函数
  TH1 = 0xf8;//设定定时器1计数高8位初值
  TL1 = 0x30;//设定定时器1计数低8位初值
  TR1 = 1;//打开定时器1
 }
 void KeyScan(void)//按键扫描函数 该函数放在定时器定时2ms的中断函数中扫描
{
  if(AddKey)//如果增加按键没按下或弹起
 {
   AddKeyLockFlag = 0;//增加按键锁定标志位清0
   AddKeyPressDelayTime = 0;//增加按键按下延时时间清0
  }   
  else if(!AddKeyLockFlag)//如果增加按键锁定标志位置1 即增加按键按下
 {
   AddKeyPressDelayTime++;//增加按键按下延时时间自加
   if(AddKeyPressDelayTime > KeyPressDeshakeTime)//如果增加按键按下延时时间大于按键按下消抖时间
  {
    AddKeyPressDelayTime = 0;//增加按键按下延时时间清0
    KeyNumber = 1;//按键键值置1 此处是单击增加 可赋给swicth()语句中的变量来对数值单击增加
    AddKeyLockFlag = 1;//增加按键锁定标志位置1
   }
  }
  else if(AddKeyPressDelayTime < KeyLongPressDelayTime)//如果增加按键按下延时时间小于按键长按延时时间
 {
   AddKeyPressDelayTime++;//增加按键按下延时时间自加
  }
  else//如果增加按键按下延时时间大于按键长按延时时间
 {
   AddKeyLongPressAddIntervalTime++;//增加按键长按连增间隔时间自加
   if(AddKeyLongPressAddIntervalTime > KeyLongPressIntervalChangeTime)//如果增加按键长按连增间隔时间大于按键长按间隔变化时间
  {
     AddKeyLongPressAddIntervalTime = 0;//增加按键长按连增间隔时间清0
     KeyNumber = 1;//按键键值置1 此处是连击增加 可赋给swicth()语句中的变量来对数值连击增加
   }
  }   
  if(DecKey)//如果减少按键没按下或弹起
 {
   DecKeyLockFlag = 0;//减少按键锁定标志位清0
   DecKeyPressDelayTime = 0;//减少按键按下延时时间清0
  }   
  else if(!DecKeyLockFlag)//如果减少按键锁定标志位置1 即减少按键按下
 {
   DecKeyPressDelayTime++;//减少按键按下延时时间自加
   if(DecKeyPressDelayTime > KeyPressDeshakeTime)//如果减少按键按下延时时间大于按键按下消抖时间
  {
    DecKeyPressDelayTime = 0;//减少按键按下延时时间清0
    KeyNumber = 2;//按键键值置2 此处是单击减少 可赋给swicth()语句中的变量来对数值单击减少
    DecKeyLockFlag = 1;//减少按键锁定标志位置1
   }
  }
  else if(DecKeyPressDelayTime < KeyLongPressDelayTime)//如果减少按键按下延时时间小于按键长按延时时间
 {
   DecKeyPressDelayTime++;//减少按键按下延时时间自加
  }
  else//如果减少按键按下延时时间大于按键长按延时时间
 {
   DecKeyLongPressDecIntervalTime++;//减少按键长按连减间隔时间自加
   if(DecKeyLongPressDecIntervalTime > KeyLongPressIntervalChangeTime)//如果减少按键长按连减间隔时间大于按键长按间隔变化时间
  {
    DecKeyLongPressDecIntervalTime = 0;//减少按键长按连减间隔时间清0
    KeyNumber = 2;//按键键值置2 此处是连击减少 可赋给swicth()语句中的变量来对数值连击减少
    }
   }
 }
 void PwmDutyCycleSet()//脉冲宽度占空比设置函数
{
  switch(KeyNumber)//按键类型筛选位
 {
   case 1 ://增加按键单击、长按触发位
           PwmValue++;//脉冲宽度值自加
           if(PwmValue > 255)//如果脉冲宽度值大于255
          {
            PwmValue = 255;//脉冲宽度值等于255
           }
           CCAP0H = CCAP0L = PwmValue;//脉冲宽度值赋给CCP/PCA/PWM模块0高低八位捕获/比较寄存器
           KeyNumber = 0;//按键键值清0
           break;//跳出
   case 2 ://减少按键单击、长按触发位
           PwmValue--;//脉冲宽度值自减
           if(PwmValue < 0)//如果脉冲宽度值小于
          {
            PwmValue = 0;//脉冲宽度值清0
           }
           CCAP0H = CCAP0L = PwmValue;//脉冲宽度值赋给CCP/PCA/PWM模块0高低八位捕获/比较寄存器
           KeyNumber = 0;//按键键值清0
           break;//跳出
   default:break;//跳出
  }
 }




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1154087.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

超融合数据库:解锁全场景数据价值的钥匙

前言 近日&#xff0c;四维纵横对外官宣已完成上亿元 B 轮融资。作为超融合数据库理念的提出者&#xff0c;三年来 YMatrix 持续在超融合数据库领域中保持精进与迭代&#xff0c;对于超融合数据库在行业、场景中的应用和理解也更为深刻。 本篇文章&#xff0c;我们将基于 YMa…

Qt QStackWidget实现透明化loading弹窗与结果展示

效果: 特点: 1、组件复用,用于工作环境中作为单例组件加载方式,作用全局任何需要进行loading显示的业务逻辑; 2、接口调用简单,只需要调用loading开始,显示成功页面,显示错误页面; 3、按钮业务逻辑只进行隐藏当前loading加载框,可根据自己需要自定义业务逻辑; 4…

用 Milvus 和 NVIDIA Merlin 搭建高效推荐系统

如何搭建一个高效的推荐系统&#xff1f; 简单来说&#xff0c;现代推荐系统由训练/推理流水线&#xff08;pipeline&#xff09;组成&#xff0c;涉及数据获取、数据预处理、模型训练和调整检索、过滤、排名和评分相关的超参数等多个阶段。走遍这些流程之后&#xff0c;推荐系…

MyBatis Plus之wrapper用法

一、条件构造器关系 条件构造器关系介绍&#xff1a; 绿色框&#xff1a;抽象类 abstract 蓝色框&#xff1a;正常 class 类&#xff0c;可 new 对象 黄色箭头&#xff1a;父子类关系&#xff0c;箭头指向为父类 wrapper介绍&#xff1a; Wrapper &#xff1a;条件构造抽象类…

技术贴 | 一文带你走进统计信息模型

一、简介 数据库中的“统计信息”是一个描述数据库中表和列信息的数据集合。优化器代价模型 (OptimizerCost Model) 依赖于查询中涉及到的表、列、谓词等对象的统计信息来选取计划&#xff0c;优化器可以利用统计信息来优化计划的选择&#xff0c;所以统计信息是代价模型中选取…

微信开放平台账号

微信开放平台账号是用于注册APP端用的微信分享、登陆、支付等功能接口的账号&#xff0c;在制作APP的过程中非常重要。通过微信开放平台&#xff0c;开发者可以接入微信支付、微信登录等功能&#xff0c;从而为APP提供更多样化的服务。 微信开放平台账号管理权限包括创建开放平…

智能井盖传感器推荐,万宾科技助力城市信息化建设

随着科技产品更新换代进程加快&#xff0c;人工智能在人们日常生活之中逐渐普及开来&#xff0c;深入人们生活的方方面面&#xff0c;影响城市基础设施建设工程。例如在大街小巷之中的井盖作为城市基础建设的一个重要部分&#xff0c;一旦出现松动倾斜或凸起等异常问题&#xf…

Linux 中如何修改终端提示符颜色?

哈喽大家好&#xff0c;我是咸鱼 我们知道默认情况下&#xff0c;Linux 终端提示符都是简单的黑白色、 这种黑白提示一方面看久了容易视觉疲劳&#xff0c;另一方面由于没有高亮显示&#xff0c;看着很不方便&#xff0c;视觉体验极差 所以我们需要修改我们的终端显示颜色&a…

想入门网络安全,这些前置准备要做好!

网上有很多关于网络安全如何学习、如何入门的内容&#xff0c;但是仍然有很多小白不懂网络安全要怎么去学习。这是由于网络安全包含的范围确实比较广&#xff0c;学习的内容也比较多&#xff0c;所以在刚开始了解的时候确实会有点搞不清楚状况。 这里有一个方法&#xff0c;不要…

前后端配合实现按钮级操作权限控制

背景 公司项目需要做到按钮级权限限制&#xff0c;至此有了该文&#xff0c;如有错误&#xff0c;请联系博主指出&#xff0c;多多感谢。 角色配置前后端操作 首先最基本的角色配置&#xff0c;配置该类角色有哪些菜单以及那些菜单的哪些按钮权限 菜单及菜单按钮由前端维护&a…

Vue Router使用VueUse更改标签页名称的工具函数

进入正题 安装 npm i vueuse/core or pnpm i vueuse/core or yarn add vueuse/corerouter/helper.js import { useTitle } from vueuse/coreexport const usePageTitle (to) > {const projectTitle import.meta.env.VITE_APP_TITLE // 将可变名抽出到 .env 内配置cons…

源码与SaaS:企业家如何选择?——一语道破真相

在数字化的时代&#xff0c;软件技术已经成为企业运营的核心驱动力。对于企业家来说&#xff0c;选择一个适合自己企业的软件开发方式至关重要。其中&#xff0c;源码和SaaS是两种常见的选择。那么&#xff0c;在这两者之间&#xff0c;企业家应该如何抉择&#xff1f; 源码&am…

excel修改日期格式为yyyy-mm-dd

1、选中要修改日期格式的列&#xff0c;鼠标右击&#xff0c;选择“设置单元格格式” 2、若“日期”格式中没有需要的格式&#xff0c;选择自定义格式&#xff0c;输入自己需要的日期格式后点击确定即可修改

简单又有效!制作产品说明书的模板工具

产品说明书在产品推广中起着至关重要的作用。它是一种不可忽视的宣传手段&#xff0c;能够向潜在客户传达产品的特点和优势。通过详细描述产品的功能、用途和特点&#xff0c;产品说明书能够帮助客户更好地了解产品&#xff0c;并激发他们对产品的兴趣。因此&#xff0c;在进行…

Mysql权限控制语句

1.创建用户 create user ky32localhost IDENTIFIED by 123456 create user&#xff1a;创建用户开头 ky32&#xff1a;用户名 localhost 新建的用户可以在哪些主机上登录 即可以使用ip地址&#xff0c;网段主机名 ky32localhost ky32192.168.233.22 ky32192.168.233.0/2…

SUE3000 1VCF750090R804 REM615面板

SUE3000 1VCF750090R804 REM615面板 蓝色波长激光的特殊特性使扫描仪适用于各种材料的高精度轮廓和尺寸测量&#xff0c;包括闪亮的表面、炽热的发光金属、有机材料(如食品、木材和木质单板)&#xff0c;以及透明或半透明材料&#xff0c;如塑料、玻璃、光学元件和薄膜/基底。…

DNS服务器使用_windows篇

1-搭建dns服务器 安装涉及内容&#xff1a;1-安装DNS服务器&#xff1b;2-DNS正向解析&#xff1b;3-DNS反向解析&#xff1b;4-DNS转发器&#xff1b;5-主、辅域名服务器&#xff1b;6-DNS子域委派服务器 二、使用方面 1-新建域 2-新建主机 三、其它内容见附件&#xff…

Playwright测试自动化工具

作者观点&#xff1a;很长时间以来&#xff0c;Selenium是QA工程师寻求测试自动化解决方案的首选测试框架。它能够测试任何浏览器&#xff08;这在IE浏览器的统治时期尤其重要&#xff09;和任何平台。然而&#xff0c;现在看来&#xff0c;那个时代已经过去了。 今天&#xf…

修复缺失d3dcompiler_43.dll问题的多种解决方案,2分钟解决d3dcompiler_43.dll文件

你是否曾遇到这样的提示&#xff1a;“程序无法启动&#xff0c;因为您的计算机上缺少d3dcompiler_43.dll”? 如果是的话&#xff0c;不用担心。 这篇文章将提供详细的步骤解决缺失d3dcompiler_43.dll的问题&#xff0c;教你怎么一步步的解决d3dcompiler_43.dll的缺失问题。 什…