找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3742|回复: 0
收起左侧

基于stc12c5a60s2单片机的呼吸灯设计

[复制链接]
ID:264029 发表于 2018-6-25 13:31 | 显示全部楼层 |阅读模式
我在用stc12c5a60s2做呼吸灯设计时遇到的问题,我想设计出几路频率变化不一样的pwm波形,我第一个是利用了C51里面的两个计数器实现了呼吸灯设计,可以使三个灯做相同频率的呼吸,代码如下://实现三个灯的呼吸

  1. #include <reg52.h>

  2. sbit PWMOUT0 = P0^0;
  3. sbit PWMOUT1 = P0^1;
  4. sbit PWMOUT2 = P0^2;

  5. unsigned char HighRH = 0;  //高电平重载值的高字节
  6. unsigned char HighRL = 0;  //高电平重载值的低字节
  7. unsigned char LowRH  = 0;  //低电平重载值的高字节
  8. unsigned char LowRL  = 0;  //低电平重载值的低字节
  9. unsigned char T1RH = 0;
  10. unsigned char T1RL = 0;
  11. unsigned long PeriodCnt = 0;

  12. void ConfigTimer1(unsigned int ms);
  13. void ConfigPWM(unsigned int fr, unsigned char dc);

  14. void main()
  15. {
  16.     EA = 1;     //开定时器总中断

  17.     ConfigPWM(100, 10);  //配置并启动PWM
  18.     ConfigTimer1(50);    //用T1定时调整占空比
  19.     while (1);
  20. }
  21. void ConfigTimer1(unsigned int ms)
  22. {
  23.     unsigned long tmp;  //临时变量

  24.     tmp = 11059200 / 12;      //定时器计数频率
  25.     tmp = (tmp * ms) / 1000;  //计算所需的计数值
  26.     tmp = 65536 - tmp;        //计算定时器重载值
  27.     tmp = tmp + 12;           //补偿中断响应延时造成的误差
  28.     T1RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
  29.     T1RL = (unsigned char)tmp;
  30.     TMOD &= 0x0F;   //清零T1的控制位
  31.     TMOD |= 0x10;   //配置T1为模式1
  32.     TH1 = T1RH;     //加载T1重载值
  33.     TL1 = T1RL;
  34.     ET1 = 1;        //使能T1中断
  35.     TR1 = 1;        //启动T1
  36. }
  37. void ConfigPWM(unsigned int fr, unsigned char dc)
  38. {
  39.     unsigned int high, low;

  40.     PeriodCnt = (11059200/12) / fr; //计算一个周期所需的计数值
  41.     high = (PeriodCnt*dc) / 100;    //计算高电平所需的计数值
  42.     low  = PeriodCnt - high;        //计算低电平所需的计数值
  43.     high = 65536 - high + 12;       //计算高电平的定时器重载值并补偿中断延时
  44.     low  = 65536 - low  + 12;       //计算低电平的定时器重载值并补偿中断延时
  45.     HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
  46.     HighRL = (unsigned char)high;
  47.     LowRH  = (unsigned char)(low>>8);  //低电平重载值拆分为高低字节
  48.     LowRL  = (unsigned char)low;
  49.     TMOD &= 0xF0;   //清零T0的控制位
  50.     TMOD |= 0x01;   //配置T0为模式1
  51.     TH0 = HighRH;   //加载T0重载值
  52.     TL0 = HighRL;
  53.     ET0 = 1;        //使能T0中断
  54.     TR0 = 1;        //启动T0
  55.     PWMOUT0 = 1;     //输出高电平
  56.         PWMOUT1 = 1;     //输出高电平
  57.         PWMOUT2 = 1;     //输出高电平
  58. }
  59. void AdjustDutyCycle(unsigned char dc)          //调整占空比
  60. {
  61.         unsigned int high, low;

  62.         high = (PeriodCnt*dc)/100;
  63.         low = PeriodCnt - high;
  64.         high = 65536 - high + 12;
  65.         low = 65536 - low + 12;
  66.         HighRH = (unsigned char)(high >> 8);
  67.         HighRL = (unsigned char)high;
  68.         LowRH = (unsigned char)(low >> 8);
  69.         LowRL = (unsigned char)low;
  70. }
  71. void InterruptTimer0() interrupt 1                        //用定时器0,实现了灯的亮灭连续变化,实现电平的反转
  72. {
  73.     if (PWMOUT0 == 1)  //当前输出为高电平时,装载低电平值并输出低电平
  74.     {
  75.         TH0 = LowRH;
  76.         TL0 = LowRL;
  77.         PWMOUT0 = 0;
  78.                 PWMOUT1 = 0;     
  79.             PWMOUT2 = 0;     
  80.     }
  81.     else              //当前输出为低电平时,装载高电平值并输出高电平
  82.     {
  83.         TH0 = HighRH;
  84.         TL0 = HighRL;
  85.         PWMOUT0 = 1;
  86.         PWMOUT1 = 1;     
  87.         PWMOUT2 = 1;
  88.     }
  89. }

  90. void InterruptTimer1() interrupt 3
  91. {
  92.         unsigned char code table[13] = {
  93.         5, 18, 30, 41, 51, 60, 68, 75, 81, 86, 90, 93, 95
  94.         };
  95.         static bit dir = 0;
  96.         static unsigned char index = 0;

  97.         TH1 = T1RH;
  98.         TL1 = T1RL;

  99.         AdjustDutyCycle(table[index]);
  100.         if(dir == 0)
  101.         {
  102.                 index++;
  103.                 if(index >= 12)
  104.                 {
  105.                         dir = 1;
  106.                 }
  107.         }
  108.         else
  109.         {
  110.                 index--;
  111.                 if(index == 0)
  112.                 {
  113.                         dir = 0;
  114.                 }
  115.         }
  116. }
  117. 可是,我并不想看到一样的频率变化,我希望三个灯变化的频率不一样,可是上述代码实现呼吸灯的效果是基于计数器的个数的,C51的计数器已经用完了,我只好把目光投向了stc12c5a60s,这里面不仅有四个计数器,而且有两路PWM输出,
  118. 我通过设置PCA,实现了通过按键可以实时改变输出波形,
  119. 代码如下:
  120. //利用按键s1对led灯的亮度调节
  121. #include"STC12C5A60S2.h"

  122. void delay(unsigned int cnt)
  123. {
  124. unsigned char i;
  125. for(;cnt>0;cnt--)
  126. for(i=0;i<250;i++);
  127. }

  128. void main()
  129. {
  130. EA = 1;     //开定时器总中断

  131. CCON=0;                 //禁止寄存器CCON中CF位的中断
  132. CL=0;                 //PCA的16位计数器低8位
  133. CH=0;                 //PCA的16位计数器高8位
  134. CMOD=0x00;         //选择系统时钟/12为计数脉冲,则PWM的频率f=sysclk/256/12

  135. //PCA模块0
  136. CCAP0H=0x80; //占空比控制,此时的占空比为50%,一路输出
  137. CCAP0L=0x80;
  138. PCA_PWM0=0x00; //控制占空比的第九位为0
  139. CCAPM0=0x42;   //允许P13作为PWM输出

  140. //PCA模块1
  141. CCAP1H=0xcc;  //占空比控制,此时的占空比为20%,一路输出
  142. CCAP1L=0xcc;
  143. PCA_PWM1=0x00;
  144. CCAPM1=0x42;  //允许P13作为PWM输出

  145. CR=1;                   //启动PCA计数器

  146. while(1)
  147. {

  148. if(P10==0)
  149. {
  150. delay(200);
  151. while(P10==0);
  152. CCAP0H+=10;           //占空比调节
  153. CCAP0L+=10;

  154. CCAP1H+=25;           //占空比调节
  155. CCAP1L+=25;
  156. }
  157. }
  158. }

  159. 可是就在我想结合两者的特点一起实现三个灯做呼吸灯,另外两个灯通过按键做使其的波形不断变化,因为这在设计上我觉得是行得通的,因为我做呼吸灯时,只涉及到51的定时器,而stc12c5a60s2很好的兼容了51的两个定时器,这样的话,应该是可以同时出现三个灯是呼吸灯,最后两个灯通过按键调节亮度,所以我就把两个函数粘贴在一起了,可是却没有出现应有的现象。
  160. 问题如下:只能通过按键对最后两个灯实现亮度调节,而呼吸灯的现象出不来。
  161. 有问题的程序如下,不知道怎样修改,还请大神解惑。
  162. //利用按键s1对led灯的亮度调节
  163. #include"STC12C5A60S2.h"

  164. sbit PWMOUT0 = P0^0;
  165. sbit PWMOUT1 = P0^1;
  166. sbit PWMOUT2 = P0^2;

  167. unsigned char HighRH = 0;  //高电平重载值的高字节
  168. unsigned char HighRL = 0;  //高电平重载值的低字节
  169. unsigned char LowRH  = 0;  //低电平重载值的高字节
  170. unsigned char LowRL  = 0;  //低电平重载值的低字节
  171. unsigned char T1RH = 0;
  172. unsigned char T1RL = 0;
  173. unsigned long PeriodCnt = 0;

  174. void ConfigTimer1(unsigned int ms);
  175. void ConfigPWM(unsigned int fr, unsigned char dc);

  176. void delay(unsigned int cnt)
  177. {
  178. unsigned char i;
  179. for(;cnt>0;cnt--)
  180. for(i=0;i<250;i++);
  181. }

  182. void main()
  183. {
  184. EA = 1;     //开定时器总中断

  185. CCON=0;                 //禁止寄存器CCON中CF位的中断
  186. CL=0;                 //PCA的16位计数器低8位
  187. CH=0;                 //PCA的16位计数器高8位
  188. CMOD=0x00;         //选择系统时钟/12为计数脉冲,则PWM的频率f=sysclk/256/12

  189. //PCA模块0
  190. CCAP0H=0x80; //占空比控制,此时的占空比为50%,一路输出
  191. CCAP0L=0x80;
  192. PCA_PWM0=0x00; //控制占空比的第九位为0
  193. CCAPM0=0x42;   //允许P13作为PWM输出

  194. //PCA模块1
  195. CCAP1H=0xcc;  //占空比控制,此时的占空比为80%,一路输出
  196. CCAP1L=0xcc;
  197. PCA_PWM1=0x00;
  198. CCAPM1=0x42;  //允许P13作为PWM输出

  199. CR=1;                   //启动PCA计数器

  200. while(1)
  201. {
  202.     ConfigPWM(100, 10);  //配置并启动PWM
  203.     ConfigTimer1(50);    //用T1定时调整占空比
  204. if(P10==0)
  205. {
  206. delay(200);
  207. while(P10==0);
  208. CCAP0H+=10;           //占空比调节
  209. CCAP0L+=10;

  210. CCAP1H+=25;           //占空比调节
  211. CCAP1L+=25;
  212. }
  213. }
  214. }

  215. void ConfigTimer1(unsigned int ms)
  216. {
  217.     unsigned long tmp;  //临时变量

  218.     tmp = 11059200 / 12;      //定时器计数频率
  219.     tmp = (tmp * ms) / 1000;  //计算所需的计数值
  220.     tmp = 65536 - tmp;        //计算定时器重载值
  221.     tmp = tmp + 12;           //补偿中断响应延时造成的误差
  222.     T1RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
  223.     T1RL = (unsigned char)tmp;
  224.     TMOD &= 0x0F;   //清零T1的控制位
  225.     TMOD |= 0x10;   //配置T1为模式1
  226.     TH1 = T1RH;     //加载T1重载值
  227.     TL1 = T1RL;
  228.     ET1 = 1;        //使能T1中断
  229.     TR1 = 1;        //启动T1
  230. }
  231. void ConfigPWM(unsigned int fr, unsigned char dc)
  232. {
  233.     unsigned int high, low;

  234.     PeriodCnt = (11059200/12) / fr; //计算一个周期所需的计数值
  235.     high = (PeriodCnt*dc) / 100;    //计算高电平所需的计数值
  236.     low  = PeriodCnt - high;        //计算低电平所需的计数值
  237.     high = 65536 - high + 12;       //计算高电平的定时器重载值并补偿中断延时
  238.     low  = 65536 - low  + 12;       //计算低电平的定时器重载值并补偿中断延时
  239.     HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
  240.     HighRL = (unsigned char)high;
  241.     LowRH  = (unsigned char)(low>>8);  //低电平重载值拆分为高低字节
  242.     LowRL  = (unsigned char)low;
  243.     TMOD &= 0xF0;   //清零T0的控制位
  244.     TMOD |= 0x01;   //配置T0为模式1
  245.     TH0 = HighRH;   //加载T0重载值
  246.     TL0 = HighRL;
  247.     ET0 = 1;        //使能T0中断
  248.     TR0 = 1;        //启动T0
  249.     PWMOUT0 = 1;     //输出高电平
  250.         PWMOUT1 = 1;     //输出高电平
  251.         PWMOUT2 = 1;     //输出高电平
  252. }
  253. void AdjustDutyCycle(unsigned char dc)          //调整占空比
  254. {
  255.         unsigned int high, low;

  256.         high = (PeriodCnt*dc)/100;
  257.         low = PeriodCnt - high;
  258.         high = 65536 - high + 12;
  259.         low = 65536 - low + 12;
  260.         HighRH = (unsigned char)(high >> 8);
  261.         HighRL = (unsigned char)high;
  262.         LowRH = (unsigned char)(low >> 8);
  263.         LowRL = (unsigned char)low;
  264. }
  265. void InterruptTimer0() interrupt 1                        //用定时器0,实现了灯的亮灭连续变化,实现电平的反转
  266. {
  267.     if (PWMOUT0 == 1)  //当前输出为高电平时,装载低电平值并输出低电平
  268.     {
  269.         TH0 = LowRH;
  270.         TL0 = LowRL;
  271.         PWMOUT0 = 0;
  272.                 PWMOUT1 = 0;     
  273.             PWMOUT2 = 0;     
  274.     }
  275.     else              //当前输出为低电平时,装载高电平值并输出高电平
  276.     {
  277.         TH0 = HighRH;
  278.         TL0 = HighRL;
  279.         PWMOUT0 = 1;
  280.         PWMOUT1 = 1;     
  281.             PWMOUT2 = 1;
  282.     }
  283. }

  284. void InterruptTimer1() interrupt 3
  285. {
  286.         unsigned char code table[13] = {
  287.         5, 18, 30, 41, 51, 60, 68, 75, 81, 86, 90, 93, 95
  288.         };
  289.         static bit dir = 0;
  290.         static unsigned char index = 0;

  291.         TH1 = T1RH;
  292.         TL1 = T1RL;

  293.         AdjustDutyCycle(table[index]);
  294.         if(dir == 0)
  295.         {
  296.                 index++;
  297.                 if(index >= 12)
  298.                 {
  299.                         dir = 1;
  300.                 }
  301.         }
  302.         else
  303.         {
  304.                 index--;
  305.                 if(index == 0)
  306.                 {
  307.                         dir = 0;
  308.                 }
  309.         }
  310. }
复制代码



评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表