STC12C5A60S2利用PCA时钟溢出做的PWM信号

发布者:闪耀星空最新更新时间:2019-11-12 来源: 51hei关键字:STC12C5A60S2  PCA时钟  PWM信号 手机看文章 扫描二维码
随时随地手机看文章

1.程序里面想详细的算法 思路, 
2.在晶振和CPU满足计算的情况下,理论是你要多少你就通过编码器调节多少
3.本程序任意频率调试是通过编码器来切换的,
4.关于精度问题 在100hz内非常准,在最大255HZ的时候相差20hz左右,  问题可能出现在 定时器计数这个位置, 我全部取整数了 所以误差比较大
如果计数的出来本来机是整数的,那频率相对准确的, 在100hz的时候就是标准的100hz
 

单片机源程序如下:
/*------------------------------------------------------------------*/
/* --- 功能  pwm输出 频率可调 -------------------------- -----------*/
/* --- STC12C5Axx                                            -------*/
/* --- 对于定时器选择的时候,应该选择16位---------------------------*/
/* --- 不应该选择16位自动重装,因为16位自动重的工作原理是当TL0------*/
/* --- 溢出的时候,会直接把TH0的值填充到TL0里面计算这样就会导致-----*/
/* --- PWM计算频率出错     -----------------------------------------*/
/* --- 定时的工作方式为。定时器0的工作模式为16位--------------------*/
/* 计算方法 例如12MHZ需要转化为300HZ,那么根据上图,首先我们需要确定
PCA时钟输入频率,根据公式 300*256=76800HZ,这个值就是我们需要的PCA时
钟输入频率。现在问题就是 ,我们怎么把12MHZ,转化为76.8KHZ,
12000KHZ/76.8KHZ=156.25  ,这个156.25就是分频基数,而这个分频基数由
我们的定时器溢出参数来设定,意思就是当我们定时器如果计数156.25溢出就
可以做到分频基数为156.25, 所以我们在设置定时器0的计数起始值就
是65536-156=65380,对应TH0=0XFF,TL0=0X64。    0XFF=255   0X64=100
初始是如何分离的计算方法 65380/256=255 ps:取的整数,然后用255*256=65280
再用65380-65280=100这个就是 65380对256求于的个数放在TL0里面也就是0X64
那么TH0就应该放255将255转化为16进制数为0xff   */
/*整体计算公式(65536-12000/300*256)/256
/* article, please specify in which data and procedures from STC    */
/*------------------------------------------------------------------*/
/*按键k1  k2  分别接在 P0^6 P^7口  用的是独立键盘*/
/*实现的功能是,控制CR的开通和关断来实现混频效果*/
/*第二次修改时间2019-10-6*/
/*作者 Alan*/


#include
#include
//#include
#define FOSC 18432000

/*分别定义了两个不高低位的变量用于保存 定时器初值,从而初值计算里面带变量计算以后保存到这个变量 这时候就能在中断正常重新装初值了,也不会出错*/
uint8_t  TH,TL;      

/*上一次的状态*/
uint8_t  Last_Amb_Status =  0;        

/*该变量用于保存按键值*/
uint8_t  Sd_Key_Value    =  0;

uint8_t  Sd_Key_Value2    =  0;        


/*编码器三个I/O的定义 分别为,A口 B口 sdKey */
sbit  Pin_Portry_A=P2^4 ;
sbit  Pin_Portry_B=P2^3 ;     
sbit  Pin_Portry_Sd=P2^2 ;

/*testing 测试端口 暂时不用*/
sbit  BUZ = P3^0;

sbit  LED = P3^7;

sbit  k1  = P0^6;

sbit  k2  = P0^7;

sbit  LED_1 = P0^5;


unsigned char flag=0;

uint8_t Data_key2(uint8_t *key_val2);


/*延时1ms级函数2*/

void delay(unsigned int z)
{
        unsigned int  x,y;
        for(x=z;x>0;x--)
                for(y=135;y>0;y--);

}


/*副频自动变化*/          //有缺陷 放弃  重新构思    但是这里取消了  不影响主频哈     

void fuping_bianhua(uint8_t XHZ)
{
       uint8_t i;
         for(i=0;i          {
            CR = 1; 
                delay(25);   
            CR = 0;
                delay(25);
           }         


/*旋转编码器调整副频*/

uint8_t Data_key2(uint8_t *key_val2)             //*key_val这个是一个指针吗  
{
    //这个counter是为了防止没有键值动作时,程序一直在这里等待
    //具体的等待时间应该根据编码开关的脉冲周期和程序的执行周期来确定
    //可以根据实际情况进行调整,连续测试的时候,可以先去掉此限定条件
    uint16_t wait_counter = 100000;          //counter等待的时间

        uint8_t temp_key_val2 = *key_val2;  
                                                        //temp_key_val 这个是char型的变量 最大255 所以不需要设置最大值

        Last_Amb_Status = Pin_Portry_A;            //保存采样前的A口状态

        //开始采样端口A的跳变边沿,如果没有产生跳变
        //A口的当前采样值和之前保存的值是一样的,异或后值为0
        //while持续等待两个值不同时,跳过while执行下一步骤,如果等待到wait counter为0 的时候就跳出,然后执行下一步;


        while( !(Pin_Portry_A ^ Last_Amb_Status) && --wait_counter); 



        if(!wait_counter)  //在while语句期间  如果A口发生变化 除了跳出 while 同时也跳过这里 这里不能打冒号 
         

        
        return  0;           //跳过这里


        //此时采样B口的电平
        //如果B口的值和采样A口跳变沿之前的值相同,判断为顺时针旋转
        //如果B口的值和采样A口跳变沿之前的值不同,判断为逆时针旋转


        
        if(!(Pin_Portry_B ^ Last_Amb_Status))
        {
           //顺时针旋转
            temp_key_val2++;



                  if(temp_key_val2 < 2)
                      
                         temp_key_val2 = 2;

                  if(temp_key_val2 > 40);  //如果大于40就截止  限制最大
                     
                         temp_key_val2 = 2;         //重新设置为2

                        *key_val2 = temp_key_val2;  

                
                  return  1;
           }
            
        else if(Pin_Portry_B ^ Last_Amb_Status)          //和上面正转工作过程一样          zc注释
        {
           
            //逆时针旋转
            temp_key_val2--;

                if(temp_key_val2 > 40)  //如果逆时针大于40就截止
                     
                temp_key_val2 = 2;           //重新设置为2

                if(temp_key_val2 <= 2)          //如果小于2 就设置为最大40

                        temp_key_val2 = 40;

                        *key_val2 = temp_key_val2;

                  return  1;
        }

        return 0;
}



/* 定时器配置与初始化*/
void   Timer0Init(void)
{

    /*定义一个32位整形变量 temp 存放编码器初值*/
        uint32_t temp = 5;

        /*设置定时器0位1T模式*/
        /*先将tmod高4位保存为1 “TMOD=$=0XF0”,这样是防止多个定时器使用的时候,直接赋值导致其它定时器工作异常,或者是各定时器无法突出自己的作用*/
        /*通过上面保存了高4位后,接下来进行或运算"TMOD=|=0X01",从而只是将我们需要的位打开其它全部关闭,这样非常稳妥,互补相干*/
        AUXR |= 0x80;                
        TMOD &= 0xF0;                
        TMOD |= 0x01;
                        
        /*把要记的次数,通过下面的运算,算出来以后,保存到temp里面,供定时器装初值用*/
        temp = 0x10000-(18432000/(temp*256));

        /*temp内部保存的次数,分别装在定时器的高8位和低8位*/
        TH0  = TH = temp / 256;                
        TL0  = TL = temp % 256;                //设置定时器初值

        /*启动定时器相关功能,清楚标志位,启动定时器TR0,开总中断,开定时器中断ET0*/
        TF0 = 0;                //清除TF0标志
        TR0 = 1;                //定时器0开始计时
        EA=1;
        ET0=1;



}

        /*对key函数声明*/
    uint8_t Data_key(uint8_t *key_val);

        /*对频率更新函数声明*/
    void pinglvgengxing(uint8_t key_val);


void main(void)

{



        Timer0Init();         //初始化定时器配置函数

    CCON = 0;
    CL = 0;
    CH = 0;

    /*将PCA fosc模式设置为 定时器0溢出率*/
    CMOD = 0x04;

        /*setting CCAP0H 脉宽为50%输出*/
    CCAP0H = CCAP0L = 0x80;   
              
        /*setting PCA模式为8bit自动重装模式*/
    CCAPM0 = 0x42; 
                        
           /*setting CCAP1H 脉宽为50%输出*/
    CCAP1H = CCAP1L = 0x80;        

    PCA_PWM1 = 0x00;

        /*setting PCA模式为8bit自动重装模式*/
    CCAPM1 = 0x42;

        /*PCA时钟开始运行,计数, 输出pwm信号*/
    CR = 1;                         
        

  while (1)
        {        

            

          if(0 == flag)
         {
                LED=0;
               if(Data_key(&Sd_Key_Value));

                else if(Pin_Portry_Sd!=1)          // 判断按键是否被按下
               {
                        
                                
                           delay(5);           //消抖动

                       if(Pin_Portry_Sd!=1)  //再次判断

                              while(!Pin_Portry_Sd);

                                 LED=1;
                                    flag=1;
                          
                   }
          }
                         
                 else  if(1 == flag)
                   {
                                   LED_1=0;
                        if(Data_key2(&Sd_Key_Value2));
                                 
                        if(Pin_Portry_Sd!=1)  //再次判断
                                {
                                 delay(5);

                                while(!Pin_Portry_Sd);
                                  LED_1=1;
                                    flag=0;
                                 }
                         
                 }

          
                  
                        fuping_bianhua(Sd_Key_Value2);



                   // 如果要在1602上显示对应的频率,直接将“Sd_Key_Value2”变化写数据到1602
                   //记住要分离式数据哦   这个设计是0-255HZ  误差有点大 开到255的时候频率误差在20-30hz
                   //这个误差主要是来自PCA时钟运算这里,主要是计算的时候出现了小数点就省略了 如果从新
                   //将小数点保留 频率是很准的   在100hz内的频率基本就很准的  自己去调整吧

                 
                        pinglvgengxing(Sd_Key_Value);
                

   }

}


/*频率更新函数*/
void pinglvgengxing(uint8_t key_val)
{
        uint32_t temp;
        //关闭定时器中断
        //关闭全局中断
        //失能定时器
        //清除定时器溢出标志位
        ET0 = 0;
        EA  = 0;
        TR0 = 0;
        TF0 = 0;

        //重新初始化定时初值
        temp = 0x10000-18432000/(key_val*256) ;
        TH0 =TH= temp/256;                //设置定时初值
        TL0 =TL= temp%256;                //设置定时初值

        //开启全局中断
        //开启定时器中断
        //使能定时器
        EA  = 1;
        ET0 = 1;
        TR0 = 1;
}


/*主频按键函数*/
uint8_t Data_key(uint8_t *key_val)             //*key_val这个是一个指针吗  
{
    //这个counter是为了防止没有键值动作时,程序一直在这里等待
    //具体的等待时间应该根据编码开关的脉冲周期和程序的执行周期来确定
    //可以根据实际情况进行调整,连续测试的时候,可以先去掉此限定条件
    uint16_t wait_counter = 100000;          //counter等待的时间

        uint8_t temp_key_val = *key_val;  //这个是一个指针变量吗?  如果是  那它是指向 (Sd_Key_Value) 这里面的吗     //我还没有学过指针哈哈哈

        /*把A口的值保存到当前状态 变量里面*/  
        Last_Amb_Status = Pin_Portry_A;            //保存采样前的A口状态

        //开始采样端口A的跳变边沿,如果没有产生跳变
        //A口的当前采样值和之前保存的值是一样的,异或后值为0
        //while持续等待两个值不同时,跳过while执行下一步骤,如果等待到wait counter为0 的时候就跳出,然后执行下一步;


        while( !(Pin_Portry_A ^ Last_Amb_Status) && --wait_counter); 



        if(!wait_counter)  //在while语句期间  如果A口发生变化 除了跳出 while 同时也跳过这里 这里不能打冒号 
         


        return  0;           //跳过这里


        //此时采样B口的电平
        //如果B口的值和采样A口跳变沿之前的值相同,判断为顺时针旋转
        //如果B口的值和采样A口跳变沿之前的值不同,判断为逆时针旋转


        
        if(!(Pin_Portry_B ^ Last_Amb_Status))
        {
           //顺时针旋转
            temp_key_val++;


                
                  if(temp_key_val < 5)
                      
                         temp_key_val = 5;

                          //if(temp_key_val > 40)  //如果大于40就截止
                     
                        // temp_key_val = 2;         //重新设置为2

                 //我感觉这个是一个指针变量  将按键值传递给指针 然后指针指向Sd_Key_Value地址 然后就可以将 temp_key_val;结果传递给Sd_Key_Value
                        *key_val = temp_key_val;  

                
                  return  1;
           }
            
        else if(Pin_Portry_B ^ Last_Amb_Status)          //和上面正转工作过程一样          zc注释
        {
            //逆时针旋转

                
                 temp_key_val--;

            //        if(temp_key_val2 > 40)  //如果逆时针大于40就截止
                     
              //        temp_key_val2 = 2;           //重新设置为2

                     if(temp_key_val <= 5)   

                         temp_key_val =255;            //限制最小  

                
                        *key_val = temp_key_val;
                
                  return  1;
                 
        }
        
         
        return 0;
}




/*定时器0中断*/
void tm0_isr(void) interrupt 1 using 1
{
     TH0 =TH;                //设置定时初值
     TL0 =TL;                //设置定时初值
}

[1] [1]
关键字:STC12C5A60S2  PCA时钟  PWM信号 引用地址:STC12C5A60S2利用PCA时钟溢出做的PWM信号

上一篇:51单片机DS18B20温度传感四位数码管显示报警
下一篇:教你使用一个单片机IO口控制RGB彩灯,单总线LED灯使用教程

推荐阅读最新更新时间:2024-11-04 18:19

利用MCS-51单片机PWM信号进行舵机控制
在机器人机电控制系统中,舵机控制效果是性能的重要影响因素。舵机可以在微机电系统和航模中作为基本的输出执行机构,其简单的控制和输出使得单片机系统非常容易与之接口。 舵机是一种位置伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。其工作原理是:控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。 图1 舵机的控制要求 舵机的控制信号是PW
[单片机]
利用MCS-51单片机<font color='red'>PWM</font><font color='red'>信号</font>进行舵机控制
基于STC12C5A60S2的双电源供电智能控制系统设计
摘要:文章介绍了基于STC12C5A60S2单片机的双电源供电智能控制系统,实现对主电源和备用电源的实时监测,保证供电的连续性和可靠性。文中阐述丫系统的整体设计方案、硬件电路设计、软件设计及后台监控的设计。通过理论分析及实践汪明能有效的检测当前主备电路的电压值并实现双电源之间的准确转换,相应状态可以通过GSM模块发送给监控主机和相关操作人员,具有重要的现实意义。 0 引言 随着国民经济的迅速发展,人们对供电连续性、可靠性的要求越来越高,对于不允许断电的重要场合,如医院手术室、高层建筑安全保障系统、热电站、化工企业、银行等,都要求配备至少两路电源来保证供电的连续性。因此,需要一种能在两路电源之间进行自动转换的系统,以保证正在使用
[测试测量]
基于<font color='red'>STC12C5A60S2</font>的双电源供电智能控制系统设计
51单片机控制PWM信号实现直流电机转速控制的方法
设计中采用了专门的芯片组成了PWM信号的发生系统并且对PWM信号的原理、产生方法以及如何通过软件编程对PWM信号占空比进行调节从而控制其输入信号波形等均作了详细的阐述。另外本系统中使用了红外对管对直流电机的转速进行测量,经过整形电路后将测量值送到单片机,并且最终作为反馈值输入到单片机进行PID运算从而实现了对直流电机速度的控制。在软件方面,文章中详细介绍了PID运算程序初始化程序等的编写思路和具体的程序实现。 1 单片机最小系统:单片机最小系统由51单片机,晶振电路,复位电路,电源组成。大家都比较熟悉,这里不再赘述。 2 四位数码管显示:在应用系统中,设计要求不同,使用的LED显示器的位数也不同,因此就生产了位数,尺寸,型
[单片机]
51单片机控制<font color='red'>PWM</font><font color='red'>信号</font>实现直流电机转速控制的方法
利用单片机PWM信号进行舵机控制
基于单片机的舵机控制方法具有简单、精度高、成本低、体积小的特点,并可根据不同的舵机数量加以灵活应用。 在机器人机电控制系统中,舵机控制效果是性能的重要影响因素。舵机可以在微机电系统和航模中作为基本的输出执行机构,其简单的控制和输出使得单片机系统非常容易与之接口。 舵机是一种位置伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。其工作原理是:控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动
[单片机]
STC12C5A60S2 AD转换C语言示例程序(ADC查询方式)
STC12C5A60S2 C语言示例程序(ADC查询方式) #include reg51.h #include intrins.h #define FOSC 18432000L #define BAUD 9600 typedef unsigned char BYTE; typedef unsigned int WORD; /*Declare SFR associated with the ADC */ sfr ADC_CONTR = 0xBC; //ADC control register sfr ADC_RES = 0xBD; //ADC high 8-bit result registe
[单片机]
STM32F407ZGT6实现输入捕获RX1002八路PWM信号
1. 首先介绍接收机的PWM输出类型。 通过示波器测量,可以知道: 1. 华科尔1002接收机的输出为PWM波,每个通道周期为22ms,高电平为3.3V。其中高电平的us数表示了该通道当前的舵量。比如说:当前俯仰通道默认中值为1500,该通道输出的PWM波的高电平即为1500us。 2. PWM转PPM的输出为PPM编码模式。其中高电平为5V左右(可能会有5.8V),具体的信号模式看PPM的编码介绍。在每个PPM帧之间有大于5ms的低电平时间表示帧的开始和结束。 具体如图所示: 图1 这是某通道输出舵量为1500时的PWM波形 图2 PPM波形图 2.输入捕获测试。 (1)先测试前四个通道的高电平捕获
[单片机]
STM32F407ZGT6实现输入捕获RX1002八路<font color='red'>PWM</font><font color='red'>信号</font>
STC12C5A60S2设计的马弗炉温度控制器方案
马弗炉是高性能机电一体化的新一代智能产品,适用于煤炭、电力、化工、冶金等行业和部门进行工业分析。马弗炉温度控制器设计以单片机STC12C5A60S2作为控制中心,采用PID控制算法和自适应控制技术,自动调整预加热温度,并可以存储记忆,确保试验顺利完成,自动化程度高。 1.马弗炉主要技术指标 测温范围:0~1000℃ 测温精度:±3℃ 控温精度:±10℃(在250~1000℃范围内) 升温时间:(室温~920℃)≤30min 电源:AC220V±22V@50Hz±1Hz 功率:3.5kW 具有快速灰化和缓慢灰化、挥发分、罗加指数、黏结指数等四个专用加热程序;另外,温度控制器有一个自选程序,通过按键可选择所需设定的温度和保温时间。
[单片机]
<font color='red'>STC12C5A60S2</font>设计的马弗炉温度控制器方案
stc12c5a60s2 0-30电压测量 有注释
#include STC12C5A60S2.H #include intrins.h #define uchar unsigned char #define uint unsigned int #define ulong unsigned long /*Define ADC operation const for ADC_CONTR*/ #define ADC_POWER 0x80 //ADC 电源控制位 10000000 0X80 / #define ADC_FLAG 0x10 //ADC 完成标志 00010000 0x10 #define ADC_START 0x08
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved