设为首页收藏本站淘宝杂货铺

从F到0 - From F to 0

 找回密码
 注册已关闭
搜索
查看: 2414|回复: 2
收起左侧

DIY全彩渐变灯随机颜色渐变程序 蜂鸣器放歌 2合1 可同时工作

[复制链接]
发表于 2017-6-23 22:23:53 | 显示全部楼层 |阅读模式


  1. /************************
  2. DIY全彩渐变灯随机颜色渐变程序 蜂鸣器放歌 2合1 可同时工作
  3. 蜂鸣器放歌程序用到两个定时器,分别用于精准控制频率和时间。
  4. 贺卡音乐芯片唯一的制作方法,可加入其他功能,音乐数据可随意修改。
  5. 可直接移植到其他芯片中,在中断外的程序会严重影响到软件延时。
  6. 单片机型号:STC15F104E或STC15L104E或其他8脚STC芯片。
  7. 晶振频率:12Mhz
  8. 硬件连接:
  9. 红色到P3.3
  10. 公共极直接到P3.2
  11. 绿色到P3.1
  12. 蓝色到P3.0
  13. 蜂鸣器连接P3.5(不同型号芯片可能会有不同,根据寄存器决定)
  14. 版本更新历史:
  15. 1.修正为逐渐导通扫描LED,防止3v芯片不接电阻,多个LED同时导通而导致颜色显示不正常。
  16. 2.添加了颜色渐变功能。
  17. 3.P3.0~P3.3口可直接连接4脚全彩LED,可设置共阴共阳。
  18.         注意:
  19.                 片内必须包含控制IO口输出频率的特殊功能寄存器,否则将无法输出频率。
  20.                 晶振频率过高会导致低频信号不能鸣叫,同时耗电量增加,看门狗更容易跑飞,
  21.                 过低则会导致时间频率误差加大。
  22. ************************/

  23. #include <reg51.h>
  24. #include<intrins.h>
  25. //#include <stdlib.h>
  26. //#include <stdio.h>
  27. //#include <eeprom.h>

  28. unsigned char rb=0;
  29. unsigned char rc=0;
  30. unsigned char rd=0;
  31. unsigned char re=0;
  32. unsigned char rf=0;
  33. unsigned char rg=0;
  34. unsigned char rh=0;
  35. unsigned char ri=0;


  36. #define FOSC 12000000L //晶振频率
  37. #define public 1 //共阳为1,共阴为0
  38. unsigned int T1MS=65536-FOSC/1000; //计算定时器计时1毫秒需要的时间
  39. sbit io=P3^2; //公共极
  40. sbit io_blue=P3^0; //蓝色LED通道
  41. sbit io_green=P3^1;//绿色LED通道
  42. sbit io_red=P3^3;//红色LED通道
  43. sbit key=P3^4;
  44. //***********************
  45. sfr P3M0 = 0xB1; // 定义P3M1寄存器
  46. sfr P3M1 = 0xB2; // 定义P3M0寄存器

  47. sfr eeprom_data  =  0xC2; //EEPROM数据地址寄存器
  48. sfr eeprom_addrh =  0xC3; //EEPROM高8位地址寄存器
  49. sfr eeprom_addrl =  0xC4; //EEPROM低8位地址寄存器
  50. sfr eeprom_cmd   =  0xC5; //EEPROM模式操作寄存器
  51. sfr eeprom_trig  =  0xC6; //EEPROM命令有效寄存器
  52. sfr eeprom_contr =  0xC7; //EEPROM命令有效寄存器

  53. sfr CLK_DIV     = 0x97;
  54. sfr AUXR      = 0x8e;               //辅助特殊功能寄存器
  55. sfr INT_CLKO  = 0x8f;               //唤醒和时钟输出功能寄存器
  56. sbit T1CLKO   = P3^5;               //蜂鸣器连接VCC和P3.5

  57. bit bit_blue=1;
  58. bit bit_green=1;
  59. bit bit_red=1;
  60. bit j=0;
  61. unsigned char t=0;
  62. unsigned int p=0; //延迟毫秒替减,为0则切换频率
  63. unsigned char m=0;//当前音乐数据指向的指针
  64. unsigned int code md[212]={ //音乐数据,包含频率和持续时间的数据。
  65. 0,580,600,300,600,100,900,200,1200,350,900,170,1200,200,1500,170,1600,260,1500,260,1180,180,1350,350,0,360,600,250,600,100,900,170,1200,360,900,170,1200,180,1500,170,1600,260,1500,260,1200,170,1330,200,0,150,1500,240,1330,100,1200,350,1200,270,1330,80,1500,170,2000,180,2000,175,1800,170,1600,170,1500,180,1330,170,1600,180,1500,180,1200,170,900,350,1000,350,1000,250,1100,100,1200,180,1500,350,1200,180,1340,170,1500,180,1600,170,1670,170,1800,190,1340,150,900,150,750,200,600,300,600,100,900,200,1200,350,900,170,1200,200,1500,170,1600,260,1500,260,1180,180,1350,350,0,360,600,250,600,100,900,170,1200,360,900,170,1200,180,1500,170,1600,260,1500,260,1200,170,1330,200,0,150,1500,260,1330,90,1200,350,1200,260,1330,90,1500,170,2000,350,1800,170,1600,170,1500,180,1330,170,1600,170,1500,180,1200,170,900,350,1000,350,1000,260,1100,90,1200,170,1500,340,1200,180,1330,170,1200,170,1120,180,1330,170,1200,350,0,250
  66. };

  67. unsigned char rand(){ //计算随机数 算法
  68.                 rb=(rc+3)*3;rc=(rd-3)*3;rd=(re+3)*3;re=(rf-3)*3;
  69.                 rf=(rg+3)*3;rg=(rh-3)*3;rh=(ri+3)*3;ri=(rb-3)*3;

  70.         if(rb > 127) rc = rc^127;
  71.         if(rc < 127) rd = rd^127;
  72.         if(rd > 127) re = re^127;
  73.         if(re < 127) rf = rf^127;
  74.         if(rf > 127) rg = rg^127;
  75.         if(rg < 127) rh = rh^127;
  76.         if(rh > 127) ri = ri^127;
  77.         if(ri < 127) rb = rb^127;

  78.         return rb^rc^rd^re^rf^rg^rh^ri;
  79. }

  80. void srand(unsigned char i){
  81. rb=rand()^i;
  82. rc=rand()^i;
  83. rd=rand()^i;
  84. re=rand()^i;
  85. rf=rand()^i;
  86. rg=rand()^i;
  87. rh=rand()^i;
  88. ri=rand()^i;

  89. }


  90. void InitTimer0(void){ //初始化1ms中断定时器
  91.     TMOD = 0x01;
  92.     TL0 = T1MS;                     //设置计数器低8位
  93.     TH0 = T1MS >> 8;                    //设置计数器高8位
  94.     EA = 1;
  95.     ET0 = 1;
  96.     TR0 = 1;
  97. }





  98. void set_hz(unsigned int hz){ //设置蜂鸣器频率
  99.     if(0 < (int)(65536-FOSC/2/hz)) { //频率计算溢出
  100.         hz=32768; //设置频率为32768Hz
  101.         }

  102.     TMOD = 0x00;                    //设置定时器为模式1(16位自动重装载)
  103.     TMOD &= ~0x40;                  //C/T1=0, 对内部时钟进行时钟输出
  104.     TL1 = (65536-FOSC/2/hz);                 //初始化计时值
  105.     TH1 = (65536-FOSC/2/hz) >> 8;
  106.     TR1 = 1;  //开始计数



  107. }



  108. void eeprom_init(){ //EEPROM初始化程序
  109.         eeprom_contr        = 0x83;                //把第7位置1允许EEPROM可以读写
  110.         eeprom_cmd         = 0x00;                //待机模式无ISP操作
  111.         eeprom_addrh        = 0x00;
  112.         eeprom_addrl        = 0x00;

  113. }

  114. unsigned char eeprom_read_dat(unsigned char addr_h,unsigned char addr_l){ //读取EEPROM数据
  115.         unsigned char e_dat = 0x00;
  116.         eeprom_cmd         = 0x01;                //模式选择为读EEPROM
  117.         eeprom_addrh        = addr_h;
  118.         eeprom_addrl        = addr_l;
  119.         eeprom_trig        = 0x5A;                //使命令有效
  120.         eeprom_trig        = 0xA5;                //使命令有效
  121.         e_dat                = eeprom_data;
  122.         return e_dat;
  123. }

  124. void eeprom_write_dat(unsigned char addr_h,unsigned char addr_l,unsigned char w_dat){ //写入EEPROM数据
  125.         eeprom_cmd         = 0x02;                //模式选择为写EEPROM
  126.         eeprom_addrh        = addr_h;
  127.         eeprom_addrl        = addr_l;
  128.         eeprom_data        = w_dat;
  129.         eeprom_trig        = 0x5A;                //使命令有效
  130.         eeprom_trig        = 0xA5;                //使命令有效

  131. }

  132. void eeprom_erase_dat(unsigned char addr_h,unsigned char addr_l){ //擦除EEPROM数据
  133.         eeprom_cmd         = 0x03;                //模式选择为擦除EEPROM
  134.         eeprom_addrh        = addr_h;
  135.         eeprom_addrl        = addr_l;
  136.         eeprom_trig        = 0x5A;                //使命令有效
  137.         eeprom_trig        = 0xA5;                //使命令有效
  138. }



  139.         unsigned char delay_led=0; //LED延时
  140.         unsigned char srand_add=0; //随机数种子(累加)
  141.         unsigned char red_size=0; //当前红色LED亮度
  142.         unsigned char green_size=0;//当前绿色LED亮度
  143.         unsigned char blue_size=0;//当前蓝色LED亮度
  144.         unsigned char new_red_size=0; //到达的红色LED亮度
  145.         unsigned char new_green_size=0;//到达的绿色LED亮度
  146.         unsigned char new_blue_size=0;//到达的蓝色LED亮度
  147.         unsigned int delay_rand=0; //随机延时
  148.         void set_led_color(unsigned char red,unsigned char green,unsigned char blue){//设置LED颜色(3路不同占空比方波)
  149.         unsigned char input_red,input_green,input_blue;
  150.         unsigned char rgb_switch=1; //RGB切换开关,1是红色,2是绿色,3是蓝色。
  151.         unsigned char while_delay=0xFF; //该变量循环替减,变量等于0后退出循环。
  152.         unsigned char red_delay=input_red; //红色LED占空比
  153.         unsigned char green_delay=input_green; //绿色LED占空比
  154.         unsigned char blue_delay=input_blue; //蓝色LED占空比
  155.         unsigned char not_red_delay=0xFF-input_red; //红色LED占空比【位取反】
  156.         unsigned char not_green_delay=0xFF-input_green; //绿色LED占空比【位取反】
  157.         unsigned char not_blue_delay=0xFF-input_blue; //蓝色LED占空比【位取反】
  158.         bit red_on=1;bit green_on=1;bit blue_on=1; //LED亮灭状态,1灭0亮。
  159.         bit not_red=1;bit not_green=1; bit not_blue=1; //是否处理某颜色通道 1处理0不处理

  160.                 if(public == 1){ //共阳极

  161.                         input_red=0xFF-red; //红色位取反
  162.                         input_green=0xFF-green; //绿色位取反
  163.                         input_blue=0xFF-blue; //蓝色位取反
  164.                 } else { //共阴级

  165.                         input_red=red; //红色位赋值
  166.                         input_green=green; //绿色位赋值
  167.                         input_blue=blue; //蓝色位赋值

  168.         }
  169.                


  170.                 if(red==0x00){ //红色亮度等于0
  171.                 not_red=0; //不处理红色通道
  172.                 bit_red=public; //红色亮灭等于公共极
  173.                 }

  174.                 if(red==0xFF){ //红色亮度等于255
  175.                 not_red=0; //不处理红色通道
  176.                 bit_red=!public; //红色亮灭等于取反公共极
  177.                 }
  178.                                 if(green==0x00){ //绿色亮度等于0
  179.                                 not_green=0; //不处理绿色通道
  180.                                 bit_green=public; //绿色亮灭等于公共极
  181.                                 }

  182.                                 if(green==0xFF){ //绿色亮度等于255
  183.                                 not_green=0; //不处理绿色通道
  184.                                 bit_green=!public; //绿色亮灭等于取反公共极
  185.                                 }

  186.                                         if(blue==0x00){ //蓝色亮度等于0
  187.                                         not_blue=0; //不处理蓝色通道
  188.                                         bit_blue=public; //蓝色亮灭等于公共极
  189.                                         }

  190.                                         if(blue==0xFF){ //蓝色亮度等于255
  191.                                         not_blue=0; //不处理蓝色通道
  192.                                         bit_blue=!public; //蓝色亮灭等于取反公共极
  193.                                         }



  194.                 while( while_delay != 0x00 && not_red_delay + red_delay + not_green_delay + green_delay + not_blue_delay + blue_delay  != 0x00){ //所有替减变量大于或等于0
  195.                 while_delay--; //循环变量替减
  196.                 if(bit_red==!public){ //红色LED缓存区与公共极相反
  197.                         io_red=!public; //红色LED的I/O接口等于取反公共极,可以构成回路,点亮LED。
  198.                         io_green=public;//绿色LED的I/O接口等于公共极,无法构成回路,熄灭LED。
  199.                         io_blue=public; //蓝色LED的I/O接口等于公共极,无法构成回路,熄灭LED。
  200.                         //delay10us();    //延时10微秒
  201.                 }

  202.                 if(bit_green==!public){ //绿色LED缓存区与公共极相反
  203.                         io_red=public;    //红色LED的I/O接口等于公共极,无法构成回路,熄灭LED。
  204.                         io_green=!public; //绿色LED的I/O接口等于取反公共极,可以构成回路,点亮LED。
  205.                         io_blue=public;   //蓝色LED的I/O接口等于公共极,无法构成回路,熄灭LED。
  206.                         //delay10us();      //延时10微秒
  207.                 }

  208.                 if(bit_blue==!public){ //蓝色LED缓存区与公共极相反
  209.                         io_red=public;   //红色LED的I/O接口等于公共极,无法构成回路,熄灭LED。
  210.                         io_green=public; //绿色LED的I/O接口等于公共极,无法构成回路,熄灭LED。
  211.                         io_blue=!public; //蓝色LED的I/O接口等于取反公共极,可以构成回路,点亮LED。
  212.                         //delay10us();     //延时10微秒
  213.                 }




  214.                         if(rgb_switch == 1 && not_red == 1) { //处理红色通道
  215.                                  
  216.                                 if(red_on == 0){
  217.                                 bit_red=0; //将LED亮灭状态放入缓存区。
  218.                                
  219.                                 not_red_delay--; //红色LED反占空比减1
  220.                                 if(not_red_delay == 0) red_on=1; //红色LED亮灭状态放入缓存区
  221.                                 }

  222.                                 if(red_on == 1){
  223.                                 bit_red=1; //将LED亮灭状态放入缓存区。
  224.                                
  225.                                 red_delay--; //红色LED占空比减1
  226.                                 if(red_delay == 0) red_on=0; //红色LED亮灭状态放入缓存区
  227.                                 }

  228.                         rgb_switch++; //切换到绿色通道
  229.                         } else {
  230.                         rgb_switch++; //切换到绿色通道
  231.                         not_red_delay--;
  232.                         red_delay--;

  233.                         }

  234.                         if(rgb_switch == 2 && not_green == 1){ //处理绿色通道
  235.                                  
  236.                                 if(green_on == 0){
  237.                                 bit_green=0; //将LED亮灭状态放入缓存区。
  238.                                
  239.                                
  240.                                 not_green_delay--; //绿色LED反占空比减1
  241.                                 if(not_green_delay == 0) green_on=1; //绿色LED亮灭状态放入缓存区
  242.                                 }

  243.                                 if(green_on == 1){
  244.                                 bit_green=1; //将LED亮灭状态放入缓存区。
  245.                                
  246.                                
  247.                                 green_delay--; //绿色LED占空比减1
  248.                                 if(green_delay == 0) green_on=0; //绿色LED亮灭状态放入缓存区
  249.                                 }
  250.                         rgb_switch++; //切换到蓝色通道
  251.                         }  else {
  252.                         rgb_switch++; //切换到蓝色通道
  253.                         not_green_delay--;
  254.                         green_delay--;

  255.                         }

  256.                         if(rgb_switch == 3 && not_blue == 1){ //处理蓝色通道
  257.                                  
  258.                                 if(blue_on == 0){
  259.                                 bit_blue=0; //将LED亮灭状态放入缓存区。
  260.                                
  261.                                
  262.                                 not_blue_delay--; //蓝色LED反占空比减1
  263.                                 if(not_blue_delay == 0) blue_on=1; //蓝色LED亮灭状态放入缓存区
  264.                                 }

  265.                                 if(blue_on == 1){
  266.                                 bit_blue=1;  //将LED亮灭状态放入缓存区。
  267.                                
  268.                                
  269.                                 blue_delay--; //蓝色LED占空比减1
  270.                                 if(blue_delay == 0) blue_on=0; //蓝色LED亮灭状态放入缓存区
  271.                                 }
  272.                         rgb_switch=1; //切换红色通道
  273.                        

  274.                 } else {
  275.                 rgb_switch=1; //切换红色通道
  276.                         not_blue_delay--;
  277.                         blue_delay--;

  278.                 }

  279.                 }
  280. }
  281. void main(){ //主函数

  282.         AUXR |= 0xC0;
  283.         INT_CLKO |= 0x02;
  284.         INT_CLKO |= 0x10;

  285.         InitTimer0();
  286.         eeprom_init(); //EEPROM初始化
  287.         srand_add=eeprom_read_dat(0x00,0x01);//从EEPROM中读取随机随种子
  288.         eeprom_erase_dat(0x00,0x01);//从EEPROM中擦除数据
  289.         srand_add++; //随机数种子累加1个
  290.         eeprom_write_dat(0x00,0x01,srand_add); //将新种子写入EEPROM中
  291.         srand(srand_add); //初始化随机数种子,用于每次芯片上电都会产生不重复的颜色。
  292.         delay_led=0;  //LED延时计数器清零
  293.                 red_size=0x00; //当前红色值为0
  294.                 green_size=0x00; //当前绿色值为0
  295.                 blue_size=0x00; //当前蓝色值为0



  296.         if(public==1){ //如果LED为共阳则 (注:修改IO口位置需要修改这里。)

  297.                 P3M1 = 0x04;       //定义P3.2口为强上拉输出,提供更多电流以驱动LED彩灯。

  298.                         } else { //共阴则

  299.                 P3M1 = 0x0B;     //定义P3.0,P3,1,P3,3口为强上拉输出,提供更多电流以驱动LED彩灯。

  300.                 }






  301.                         io=public; //公共极赋值,否则LED就亮不了。



  302.         while(1) { //无限循环

  303.                         new_red_size=rand();//红色亮度取随机数
  304.                         new_green_size=rand();//绿色亮度取随机数
  305.                         new_blue_size=rand();//蓝色亮度取随机数


  306.                         while(new_red_size != red_size && new_green_size != green_size && new_blue_size != blue_size){ //当前颜色不等于随机到达的颜色则循环
  307.                                 if(red_size<new_red_size) { //当前红色亮度小于到达的红色亮度
  308.                                         red_size++; //红色亮度相加
  309.                                                 } else { //否则
  310.                                         red_size--; //红色亮度相减
  311.                                 }

  312.                                 if(green_size<new_green_size) { //当前绿色亮度小于到达的绿色亮度
  313.                                         green_size++; //绿色亮度相加
  314.                                                 } else { //否则
  315.                                         green_size--; //绿色亮度相减
  316.                                 }

  317.                                 if(blue_size<new_blue_size) { //当前蓝色亮度小于到达的蓝色色亮度
  318.                                         blue_size++; //蓝色亮度相加
  319.                                                 } else { //否则
  320.                                         blue_size--; //蓝色亮度相减
  321.                                 }
  322.                                        
  323.                                         delay_led=rand()&0xF+0xF; //设置替减次数
  324.                                         while(delay_led--){ //计数循环替减
  325.                                                         g:
  326.                                                 set_led_color(red_size,green_size,blue_size);  //设置输出LED颜色

  327.                                                
  328.                                                         if(j == 1){
  329.                                                                 new_red_size=rand();
  330.                                                                 new_green_size=rand();
  331.                                                                 new_blue_size=rand();
  332.                                                                 red_size=rand();
  333.                                                                 green_size=rand();
  334.                                                                 blue_size=rand();


  335.                                                         j=0;

  336.                                                         }

  337.                                         }



  338.                         }
  339.                                        
  340.                                         delay_led=rand()&0x7F+0x7F; //持续执行0~127个下面的指令。
  341.                                                 while(delay_led--){ //渐变完毕有1段时间保持颜色。
  342.                                                         set_led_color(red_size,green_size,blue_size);  //设置输出LED颜色

  343.                                                
  344.                                                         if(j == 1)goto g;


  345.                                                 }
  346.                                        
  347.                                        
  348.                                                


  349.                                





  350.                


  351.         }
  352. }

  353. void Timer0Interrupt(void) interrupt 1{ //1ms 定时器中断程序
  354.     TL0 = T1MS;                     //设置计数器低8位
  355.     TH0 = T1MS >> 8;                    //设置计数器高8位
  356. if(t>0){
  357. t--;
  358. INT_CLKO &= 0xEF;

  359. } else {
  360. INT_CLKO |= 0x10;
  361. }

  362.         if(p==0){  //延迟时间减到0
  363.                 p=md[m+1]; //设置延迟时间
  364.                 set_hz(md[m]); //设置鸣叫频率
  365.                 m+=2; //指针加2
  366.                 if(m>=212) m=0; //指针超过212则清零避免取出其他胡乱的数据
  367.         } else {
  368.                 p--; //延迟时间减1
  369.                
  370.         }
  371. }


  372. void exint2() interrupt 10          //INT2中断入口 P3.2
  373. {

  374.         if(key == 0){
  375.                 if(j==0 && t == 0){
  376.                 j=1;
  377.                 t=0xFF;
  378.                 }
  379.         }



  380. }
复制代码


发表于 2017-7-3 18:18:17 | 显示全部楼层
现在还没接触单片机,只能单纯的四处暖(水)贴。消灭零回复。
发表于 2019-4-11 23:44:05 来自手机 | 显示全部楼层
demon 发表于 2017-7-3 18:18
现在还没接触单片机,只能单纯的四处暖(水)贴。消灭零回复。

我也没接触过
您需要登录后才可以回帖 登录 | 注册已关闭

本版积分规则

QQ|手机版|Archiver|从F到0 ( 蒙ICP备17002595号-1 )
蒙公网安备15010402000325号

腾讯云安全认证

GMT+8, 2024-4-20 17:30 , Processed in 0.546031 second(s), 16 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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