久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2519|回復: 0
打印 上一主題 下一主題
收起左側

STC12C5A60S2利用PCA時鐘溢出做的PWM信號 0-255 資料共享 不對的地方望大家修改共享

[復制鏈接]
跳轉到指定樓層
樓主
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 <STC12C5A60S2.H>
#include <stdint.h>
//#include <intrins.h>
#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<XHZ;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;                //設置定時初值
}

以上程序51hei下載地址:
通過編碼器開關來控制 混頻程序V1.0.rar (37.77 KB, 下載次數: 18)

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 一区日韩| 一区二区三区久久久 | 久久久久久a | 看a网站 | 亚洲一区二区三区福利 | 日本色婷婷 | www亚洲精品 | 午夜在线影院 | 日本三级网站在线观看 | 色狠狠桃花综合 | 亚洲视频免费在线 | 国产精品毛片一区二区三区 | 亚洲一区二区三区在线视频 | 91资源在线观看 | 91在线色视频 | 亚洲精品一区中文字幕 | 一二三区av| 高清视频一区 | 情侣黄网站免费看 | 亚洲精品电影在线观看 | 在线观看免费av网站 | 国产精品99久久免费观看 | 国产片侵犯亲女视频播放 | 国产成人a亚洲精品 | 国产欧美一区二区三区久久 | 有码在线 | 在线观看午夜视频 | 成年无码av片在线 | 9191在线观看| 高清av一区| 亚洲 中文 欧美 日韩 在线观看 | aaaaaa大片免费看最大的 | 欧美一级在线观看 | 日韩精品av一区二区三区 | 在线色网 | 伊人网91| 成人一区二区在线 | 亚洲精品在线国产 | 精品久久精品 | 成人午夜免费在线视频 | 不卡av电影在线播放 |