极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1879|回复: 1

LGT8F684P 軟串口輸入控制WS2812 LED

[复制链接]
发表于 2019-2-7 21:43:10 | 显示全部楼层 |阅读模式
本帖最后由 eddiewwm 于 2019-2-7 23:01 编辑

LGT群友 Zyleon 的一個LGT8F684P 軟串口輸入控制WS2812 LED範例:
  1. #include <pic.h>
  2. #include "lgt8f684p.h"

  3. #define _XTAL_FREQ 16000000 * 2 // 16MHz, (4 / 2T) = 2

  4. //#define ws2812_pin      RC0
  5. #define rx_pin          RA6

  6. bit rx_en;
  7. unsigned char rx_recieve;
  8. unsigned char rx_recieve_count = 8;
  9. unsigned char recieved_data[6];
  10. unsigned char rx_GRB;
  11. unsigned char ws2812_prepared;
  12. const unsigned char hue_ring[] @0x200 = {0, 255, 0, 64, 255, 0, 128, 255, 0, 192, 255, 0, 255, 255, 0, 255, 192, 0, 255, 128, 0, 255, 64, 0, 255, 0, 0, 255, 0, 64, 255, 0, 128, 255, 0, 192, 255, 0, 255, 192, 0, 255, 128, 0, 255, 64, 0, 255, 0, 0, 255, 0, 64, 255,0, 128, 255, 0, 192, 255, 0, 255, 255, 0, 255, 192, 0, 255, 128, 0, 255, 64};
  13. void RXInit(void);
  14. void ws2812Init(void);
  15. void ws2812Send(unsigned char unused, unsigned char G, unsigned char R, unsigned char B);

  16. void RXInit(void)
  17. {
  18.    
  19.     ANSEL = 0x00; // IO pins digital mode
  20.     TRISA |= 1 << 6; // Set rx_pin(RA6) to input
  21.     WPUA |= 1 << 6; // Pull-up rx_pin(RA6)
  22.     OSCCON = 0x71; // Set frequency 1/1 prescaler
  23.     OPTION_REG = 0x02; // Set Timer 0 1/8 prescaler
  24.     CMCON0 = 0x07; // Disable internal comparator
  25.     BGEN = 1; // Disable internal reference voltage
  26.     ADCON1 = 3; // Set differential amplification sampling   
  27.     __delay_ms(100);   
  28.     INTCON = 0xC8; // Enable global/peripheral/RA interrupt
  29.     IOCA |= 1 << 6; // Enable rx_pin(RA6) level change interrupt

  30. }

  31. void ws2812Init(void)
  32. {
  33.    
  34.     ANSEL = 0x00;
  35.     TRISC = 0;
  36.     PORTC = 0;
  37.     rx_GRB = 0;
  38.     ws2812_prepared = 0;
  39.    
  40. }

  41. void ws2812Send(unsigned char unused, unsigned char G, unsigned char R, unsigned char B)
  42. {
  43.    
  44.     unsigned char i = 0;
  45.     #asm
  46.     bcf STATUS, 5
  47.     movlw 8;
  48.     movwf ws2812Send@i;
  49.     ws2812SetGreen:
  50.     bsf 7, 0;
  51.     btfsc ws2812Send@G, 7;
  52.     goto $+3;
  53.     nop;
  54.     bcf 7, 0;
  55.     goto $+1;
  56.     bcf 7, 0;
  57.     rlf ws2812Send@G, f;
  58.     decfsz ws2812Send@i, f;
  59.     goto ws2812SetGreen;
  60.     movlw 8;
  61.     movwf ws2812Send@i;
  62.     ws2812SetRed:
  63.     bsf 7, 0;
  64.     btfsc ws2812Send@R, 7;
  65.     goto $+3;
  66.     nop;
  67.     bcf 7, 0;
  68.     goto $+1;
  69.     bcf 7, 0;
  70.     rlf ws2812Send@R, f;
  71.     decfsz ws2812Send@i, f;
  72.     goto ws2812SetRed;
  73.     movlw 8;
  74.     movwf ws2812Send@i;
  75.     ws2812SetBlue:
  76.     bsf 7, 0;
  77.     btfsc ws2812Send@B, 7;
  78.     goto $+3;
  79.     nop;
  80.     bcf 7, 0;
  81.     goto $+1;
  82.     bcf 7, 0;
  83.     rlf ws2812Send@B, f;
  84.     decfsz ws2812Send@i, f;
  85.     goto ws2812SetBlue;
  86.     #endasm
  87.    
  88. }

  89. void main(void)
  90. {
  91.    
  92.     RXInit();
  93.     GIE = 0;
  94.     ws2812Init();
  95.    
  96.     ws2812Send(0, 128, 128, 128);
  97.     __delay_ms(1000);
  98.     ws2812Send(0, 255, 0, 0);
  99.     __delay_ms(100);
  100.     ws2812Send(0, 0, 255, 0);
  101.     __delay_ms(100);
  102.     ws2812Send(0, 0, 0, 255);
  103.     __delay_ms(100);
  104.     for (unsigned char i = 0; i < 5; i++)
  105.     {
  106.         for (unsigned char j = 0; j < 72; j += 3)
  107.         {
  108.             ws2812Send(0, hue_ring[0 + j], hue_ring[1 + j], hue_ring[2 + j]);
  109.             __delay_ms(30);
  110.         }
  111.     }
  112.     for (unsigned char i = 0; i < 200; i += 8)
  113.     {
  114.         ws2812Send(0, i, i, i);
  115.         __delay_ms(10);
  116.     }
  117.    
  118.     GIE = 1;

  119.     while(1)
  120.     {
  121.         if (rx_en);
  122.         if (ws2812_prepared)
  123.         {
  124.             unsigned char G_rx = (recieved_data[0] << 4) + recieved_data[1];
  125.             unsigned char R_rx = (recieved_data[2] << 4) + recieved_data[3];
  126.             unsigned char B_rx = (recieved_data[4] << 4) + recieved_data[5];
  127.             ws2812Send(0, G_rx, R_rx, B_rx);
  128.             ws2812_prepared = 0;
  129.         }            
  130.     }
  131.    
  132. }

  133. void interrupt pinLevelChange(void)
  134. {
  135.    
  136.     if (T0IE && T0IF)
  137.     {
  138.         T0IF = 0;
  139.         TMR0 = 256 - 104 + 2;
  140.         if (rx_recieve_count)
  141.         {
  142.             rx_recieve >>= 1;
  143.             if (rx_pin) rx_recieve |= 0x80;
  144.             rx_recieve_count--;
  145.         }
  146.         else
  147.         {
  148.             if ((rx_recieve >= '0') && (rx_recieve <= '9')) recieved_data[rx_GRB] = rx_recieve - '0';
  149.             else if ((rx_recieve >= 'A') && (rx_recieve <= 'F')) recieved_data[rx_GRB] = rx_recieve - 'A' + 10;
  150.             else recieved_data[rx_GRB] = 0;
  151.             if (++rx_GRB == 6)
  152.             {
  153.                 ws2812_prepared = 1;
  154.                 rx_GRB = 0;   
  155.             }
  156.             rx_en = 0;
  157.             T0IE = 0;
  158.             IOCA |= 1 << 6; // Enable rx_pin(RA6) level change interrupt
  159.         }
  160.     }
  161.    
  162.     else if (RAIF && (IOCA & 1 << 6) && (rx_pin == 0))
  163.     {
  164.         rx_en = 1;
  165.         IOCA &= ~(1 << 6); // Disable rx_pin(RA6) level change interrupt
  166.         TMR0 = 256 - 156 + 5;
  167.         T0IF = 0;
  168.         T0IE = 1;
  169.         rx_recieve_count = 8;
  170.         rx_recieve = 0;
  171.     }
  172.    
  173.     else T0IE = 0;
  174.    
  175.     T0IF = 0;
  176.     RAIF = 0;
  177.    
  178. }
复制代码

上例在MPLAB IDE v8.92 運行下有報錯,更改以下後克服:
ws2812Send@i equ 0x72; //count buffer
bcf status, 5;

範例內的 ws2812 的驅力波形時序 時間也跟ws2812規格書要求("1":H0.85us+L0.4us,"0": H0.4us+L0.85us)有差異,現量出來的是:"1":H0.72us+L0.62us,"0": H0.5us+L1.0us。更改ws2812Send()內的asm結構,得到更接近的波形時序:"1":H0.76us+L0.52us,"0": H0.38us+L0.88us。
  1. #include <pic.h>
  2. #include "lgt8f684p.h"

  3. #define _XTAL_FREQ 16000000 * 2 // 16MHz, (4 / 2T) = 2

  4. //#define ws2812_pin      RC0
  5. #define rx_pin          RA6

  6. bit rx_en;
  7. unsigned char rx_recieve;
  8. unsigned char rx_recieve_count = 8;
  9. unsigned char recieved_data[6];
  10. unsigned char rx_GRB;
  11. unsigned char ws2812_prepared;
  12. const unsigned char hue_ring[] @0x200 = {0, 255, 0, 64, 255, 0, 128, 255, 0, 192, 255, 0, 255, 255, 0, 255, 192, 0, 255, 128, 0, 255, 64, 0, 255, 0, 0, 255, 0, 64, 255, 0, 128, 255, 0, 192, 255, 0, 255, 192, 0, 255, 128, 0, 255, 64, 0, 255, 0, 0, 255, 0, 64, 255, 0, 128, 255, 0, 192, 255, 0, 255, 255, 0, 255, 192, 0, 255, 128, 0, 255, 64};
  13. void RXInit(void);
  14. void ws2812Init(void);
  15. void ws2812Send(unsigned char unused, unsigned char G, unsigned char R, unsigned char B);

  16. void RXInit(void) {

  17.     ANSEL = 0x00; // IO pins digital mode
  18.     TRISA |= 1 << 6; // Set rx_pin(RA6) to input
  19.     WPUA |= 1 << 6; // Pull-up rx_pin(RA6)
  20.     OSCCON = 0x71; // Set frequency 1/1 prescaler
  21.     OPTION_REG = 0x02; // Set Timer 0 1/8 prescaler
  22.     CMCON0 = 0x07; // Disable internal comparator
  23.     BGEN = 1; // Disable internal reference voltage
  24.     ADCON1 = 3; // Set differential amplification sampling   
  25.     __delay_ms(100);
  26.     INTCON = 0xC8; // Enable global/peripheral/RA interrupt
  27.     IOCA |= 1 << 6; // Enable rx_pin(RA6) level change interrupt

  28. }

  29. void ws2812Init(void) {

  30.     ANSEL = 0x00;
  31.     TRISC = 0;
  32.     PORTC = 0;
  33.     rx_GRB = 0;
  34.     ws2812_prepared = 0;

  35. }

  36. void ws2812Send(unsigned char unused, unsigned char G, unsigned char R, unsigned char B) {
  37.     unsigned char i = 0;
  38. #asm
  39.     ws2812Send@i equ 0x72; //count buffer
  40.     bcf status, 5;
  41.     movlw 8;
  42.     movwf ws2812Send@i;
  43. ws2812SetGreen:
  44. //0.125us(1H6+1L4)==>0.75us+0.5us,
  45. //0.125us(0H3+0L7)==>0.38us+0.88us
  46.     bsf 7, 0;              //1H1, 0H1, 1
  47.     btfsc ws2812Send@G, 7; //1H2, 0H3, 1/2
  48.     goto $ + 2;            //1H4, ---, 1
  49.     bcf 7, 0;              //---, 0L1, 1
  50.     nop;                   //1H5, 0L2, 1
  51.     rlf ws2812Send@G, f;   //1H6, 0L3, 1
  52.     bcf 7, 0;              //1L1, 0L4, 1
  53.     decfsz ws2812Send@i, f;//1L2, 0L5, 1/2
  54.     goto ws2812SetGreen;   //1L4, 0L7, 2
  55.     movlw 8;
  56.     movwf ws2812Send@i;
  57. ws2812SetRed:
  58.     bsf 7, 0;
  59.     btfsc ws2812Send@R, 7;
  60.     goto $ + 2;
  61.     bcf 7, 0;
  62.     nop;
  63.     rlf ws2812Send@R, f;
  64.     bcf 7, 0;
  65.     decfsz ws2812Send@i, f;
  66.     goto ws2812SetRed;
  67.     movlw 8;
  68.     movwf ws2812Send@i;
  69. ws2812SetBlue:
  70.     bsf 7, 0;
  71.     btfsc ws2812Send@B, 7;
  72.     goto $ + 2;
  73.     bcf 7, 0;
  74.     nop;
  75.     rlf ws2812Send@B, f;
  76.     bcf 7, 0;
  77.     decfsz ws2812Send@i, f;
  78.     goto ws2812SetBlue;
  79. #endasm

  80. }

  81. void main(void) {

  82.     RXInit();
  83.     GIE = 0;
  84.     ws2812Init();
  85.      
  86.     ws2812Send(0, 128, 128, 128);
  87.     __delay_ms(1000);
  88.     ws2812Send(0, 255, 0, 0);
  89.     __delay_ms(100);
  90.     ws2812Send(0, 0, 255, 0);
  91.     __delay_ms(100);
  92.     ws2812Send(0, 0, 0, 255);
  93.     __delay_ms(100);
  94.     for (unsigned char i = 0; i < 5; i++) {
  95.         for (unsigned char j = 0; j < 72; j += 3) {
  96.             ws2812Send(0, hue_ring[0 + j], hue_ring[1 + j], hue_ring[2 + j]);
  97.             __delay_ms(30);
  98.         }
  99.     }
  100.     for (unsigned char i = 0; i < 200; i += 8) {
  101.         ws2812Send(0, i, i, i);
  102.         __delay_ms(10);
  103.     }

  104.     GIE = 1;

  105.     while (1) {
  106.         if (rx_en);
  107.         if (ws2812_prepared) {
  108.             unsigned char G_rx = (recieved_data[0] << 4) + recieved_data[1];
  109.             unsigned char R_rx = (recieved_data[2] << 4) + recieved_data[3];
  110.             unsigned char B_rx = (recieved_data[4] << 4) + recieved_data[5];
  111.             ws2812Send(0, G_rx, R_rx, B_rx);
  112.             ws2812_prepared = 0;
  113.         }
  114.     }

  115. }

  116. void interrupt pinLevelChange(void) {

  117.     if (T0IE && T0IF) {
  118.         T0IF = 0;
  119.         TMR0 = 256 - 104 + 2;
  120.         if (rx_recieve_count) {
  121.             rx_recieve >>= 1;
  122.             if (rx_pin) rx_recieve |= 0x80;
  123.             rx_recieve_count--;
  124.         } else {
  125.             if ((rx_recieve >= '0') && (rx_recieve <= '9')) recieved_data[rx_GRB] = rx_recieve - '0';
  126.             else if ((rx_recieve >= 'A') && (rx_recieve <= 'F')) recieved_data[rx_GRB] = rx_recieve - 'A' + 10;
  127.             else recieved_data[rx_GRB] = 0;
  128.             if (++rx_GRB == 6) {
  129.                 ws2812_prepared = 1;
  130.                 rx_GRB = 0;
  131.             }
  132.             rx_en = 0;
  133.             T0IE = 0;
  134.             IOCA |= 1 << 6; // Enable rx_pin(RA6) level change interrupt
  135.         }
  136.     } else if (RAIF && (IOCA & 1 << 6) && (rx_pin == 0)) {
  137.         rx_en = 1;
  138.         IOCA &= ~(1 << 6); // Disable rx_pin(RA6) level change interrupt
  139.         TMR0 = 256 - 156 + 5;
  140.         T0IF = 0;
  141.         T0IE = 1;
  142.         rx_recieve_count = 8;
  143.         rx_recieve = 0;
  144.     } else T0IE = 0;

  145.     T0IF = 0;
  146.     RAIF = 0;

  147. }
复制代码

回复

使用道具 举报

 楼主| 发表于 2019-2-7 21:56:31 | 显示全部楼层
串口 9600 baud,控制為6位碼 GGRRBB,當中GG是綠色的值(00~FF),RR是紅色的值(00~FF),BB是藍色的值(00~FF)。
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2019-11-14 10:27 , Processed in 0.048552 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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