eddiewwm 发表于 2019-2-7 21:43:10

LGT8F684P 軟串口輸入控制WS2812 LED

本帖最后由 eddiewwm 于 2019-2-7 23:01 编辑

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

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

//#define ws2812_pin      RC0
#define rx_pin          RA6

bit rx_en;
unsigned char rx_recieve;
unsigned char rx_recieve_count = 8;
unsigned char recieved_data;
unsigned char rx_GRB;
unsigned char ws2812_prepared;
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};
void RXInit(void);
void ws2812Init(void);
void ws2812Send(unsigned char unused, unsigned char G, unsigned char R, unsigned char B);

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

}

void ws2812Init(void)
{
   
    ANSEL = 0x00;
    TRISC = 0;
    PORTC = 0;
    rx_GRB = 0;
    ws2812_prepared = 0;
   
}

void ws2812Send(unsigned char unused, unsigned char G, unsigned char R, unsigned char B)
{
   
    unsigned char i = 0;
    #asm
    bcf STATUS, 5
    movlw 8;
    movwf ws2812Send@i;
    ws2812SetGreen:
    bsf 7, 0;
    btfsc ws2812Send@G, 7;
    goto $+3;
    nop;
    bcf 7, 0;
    goto $+1;
    bcf 7, 0;
    rlf ws2812Send@G, f;
    decfsz ws2812Send@i, f;
    goto ws2812SetGreen;
    movlw 8;
    movwf ws2812Send@i;
    ws2812SetRed:
    bsf 7, 0;
    btfsc ws2812Send@R, 7;
    goto $+3;
    nop;
    bcf 7, 0;
    goto $+1;
    bcf 7, 0;
    rlf ws2812Send@R, f;
    decfsz ws2812Send@i, f;
    goto ws2812SetRed;
    movlw 8;
    movwf ws2812Send@i;
    ws2812SetBlue:
    bsf 7, 0;
    btfsc ws2812Send@B, 7;
    goto $+3;
    nop;
    bcf 7, 0;
    goto $+1;
    bcf 7, 0;
    rlf ws2812Send@B, f;
    decfsz ws2812Send@i, f;
    goto ws2812SetBlue;
    #endasm
   
}

void main(void)
{
   
    RXInit();
    GIE = 0;
    ws2812Init();
   
    ws2812Send(0, 128, 128, 128);
    __delay_ms(1000);
    ws2812Send(0, 255, 0, 0);
    __delay_ms(100);
    ws2812Send(0, 0, 255, 0);
    __delay_ms(100);
    ws2812Send(0, 0, 0, 255);
    __delay_ms(100);
    for (unsigned char i = 0; i < 5; i++)
    {
      for (unsigned char j = 0; j < 72; j += 3)
      {
            ws2812Send(0, hue_ring, hue_ring, hue_ring);
            __delay_ms(30);
      }
    }
    for (unsigned char i = 0; i < 200; i += 8)
    {
      ws2812Send(0, i, i, i);
      __delay_ms(10);
    }
   
    GIE = 1;

    while(1)
    {
      if (rx_en);
      if (ws2812_prepared)
      {
            unsigned char G_rx = (recieved_data << 4) + recieved_data;
            unsigned char R_rx = (recieved_data << 4) + recieved_data;
            unsigned char B_rx = (recieved_data << 4) + recieved_data;
            ws2812Send(0, G_rx, R_rx, B_rx);
            ws2812_prepared = 0;
      }            
    }
   
}

void interrupt pinLevelChange(void)
{
   
    if (T0IE && T0IF)
    {
      T0IF = 0;
      TMR0 = 256 - 104 + 2;
      if (rx_recieve_count)
      {
            rx_recieve >>= 1;
            if (rx_pin) rx_recieve |= 0x80;
            rx_recieve_count--;
      }
      else
      {
            if ((rx_recieve >= '0') && (rx_recieve <= '9')) recieved_data = rx_recieve - '0';
            else if ((rx_recieve >= 'A') && (rx_recieve <= 'F')) recieved_data = rx_recieve - 'A' + 10;
            else recieved_data = 0;
            if (++rx_GRB == 6)
            {
                ws2812_prepared = 1;
                rx_GRB = 0;   
            }
            rx_en = 0;
            T0IE = 0;
            IOCA |= 1 << 6; // Enable rx_pin(RA6) level change interrupt
      }
    }
   
    else if (RAIF && (IOCA & 1 << 6) && (rx_pin == 0))
    {
      rx_en = 1;
      IOCA &= ~(1 << 6); // Disable rx_pin(RA6) level change interrupt
      TMR0 = 256 - 156 + 5;
      T0IF = 0;
      T0IE = 1;
      rx_recieve_count = 8;
      rx_recieve = 0;
    }
   
    else T0IE = 0;
   
    T0IF = 0;
    RAIF = 0;
   
}
上例在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。
#include <pic.h>
#include "lgt8f684p.h"

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

//#define ws2812_pin      RC0
#define rx_pin          RA6

bit rx_en;
unsigned char rx_recieve;
unsigned char rx_recieve_count = 8;
unsigned char recieved_data;
unsigned char rx_GRB;
unsigned char ws2812_prepared;
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};
void RXInit(void);
void ws2812Init(void);
void ws2812Send(unsigned char unused, unsigned char G, unsigned char R, unsigned char B);

void RXInit(void) {

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

}

void ws2812Init(void) {

    ANSEL = 0x00;
    TRISC = 0;
    PORTC = 0;
    rx_GRB = 0;
    ws2812_prepared = 0;

}

void ws2812Send(unsigned char unused, unsigned char G, unsigned char R, unsigned char B) {
    unsigned char i = 0;
#asm
    ws2812Send@i equ 0x72; //count buffer
    bcf status, 5;
    movlw 8;
    movwf ws2812Send@i;
ws2812SetGreen:
//0.125us(1H6+1L4)==>0.75us+0.5us,
//0.125us(0H3+0L7)==>0.38us+0.88us
    bsf 7, 0;            //1H1, 0H1, 1
    btfsc ws2812Send@G, 7; //1H2, 0H3, 1/2
    goto $ + 2;            //1H4, ---, 1
    bcf 7, 0;            //---, 0L1, 1
    nop;                   //1H5, 0L2, 1
    rlf ws2812Send@G, f;   //1H6, 0L3, 1
    bcf 7, 0;            //1L1, 0L4, 1
    decfsz ws2812Send@i, f;//1L2, 0L5, 1/2
    goto ws2812SetGreen;   //1L4, 0L7, 2
    movlw 8;
    movwf ws2812Send@i;
ws2812SetRed:
    bsf 7, 0;
    btfsc ws2812Send@R, 7;
    goto $ + 2;
    bcf 7, 0;
    nop;
    rlf ws2812Send@R, f;
    bcf 7, 0;
    decfsz ws2812Send@i, f;
    goto ws2812SetRed;
    movlw 8;
    movwf ws2812Send@i;
ws2812SetBlue:
    bsf 7, 0;
    btfsc ws2812Send@B, 7;
    goto $ + 2;
    bcf 7, 0;
    nop;
    rlf ws2812Send@B, f;
    bcf 7, 0;
    decfsz ws2812Send@i, f;
    goto ws2812SetBlue;
#endasm

}

void main(void) {

    RXInit();
    GIE = 0;
    ws2812Init();
   
    ws2812Send(0, 128, 128, 128);
    __delay_ms(1000);
    ws2812Send(0, 255, 0, 0);
    __delay_ms(100);
    ws2812Send(0, 0, 255, 0);
    __delay_ms(100);
    ws2812Send(0, 0, 0, 255);
    __delay_ms(100);
    for (unsigned char i = 0; i < 5; i++) {
      for (unsigned char j = 0; j < 72; j += 3) {
            ws2812Send(0, hue_ring, hue_ring, hue_ring);
            __delay_ms(30);
      }
    }
    for (unsigned char i = 0; i < 200; i += 8) {
      ws2812Send(0, i, i, i);
      __delay_ms(10);
    }

    GIE = 1;

    while (1) {
      if (rx_en);
      if (ws2812_prepared) {
            unsigned char G_rx = (recieved_data << 4) + recieved_data;
            unsigned char R_rx = (recieved_data << 4) + recieved_data;
            unsigned char B_rx = (recieved_data << 4) + recieved_data;
            ws2812Send(0, G_rx, R_rx, B_rx);
            ws2812_prepared = 0;
      }
    }

}

void interrupt pinLevelChange(void) {

    if (T0IE && T0IF) {
      T0IF = 0;
      TMR0 = 256 - 104 + 2;
      if (rx_recieve_count) {
            rx_recieve >>= 1;
            if (rx_pin) rx_recieve |= 0x80;
            rx_recieve_count--;
      } else {
            if ((rx_recieve >= '0') && (rx_recieve <= '9')) recieved_data = rx_recieve - '0';
            else if ((rx_recieve >= 'A') && (rx_recieve <= 'F')) recieved_data = rx_recieve - 'A' + 10;
            else recieved_data = 0;
            if (++rx_GRB == 6) {
                ws2812_prepared = 1;
                rx_GRB = 0;
            }
            rx_en = 0;
            T0IE = 0;
            IOCA |= 1 << 6; // Enable rx_pin(RA6) level change interrupt
      }
    } else if (RAIF && (IOCA & 1 << 6) && (rx_pin == 0)) {
      rx_en = 1;
      IOCA &= ~(1 << 6); // Disable rx_pin(RA6) level change interrupt
      TMR0 = 256 - 156 + 5;
      T0IF = 0;
      T0IE = 1;
      rx_recieve_count = 8;
      rx_recieve = 0;
    } else T0IE = 0;

    T0IF = 0;
    RAIF = 0;

}

eddiewwm 发表于 2019-2-7 21:56:31

串口 9600 baud,控制為6位碼 GGRRBB,當中GG是綠色的值(00~FF),RR是紅色的值(00~FF),BB是藍色的值(00~FF)。
页: [1]
查看完整版本: LGT8F684P 軟串口輸入控制WS2812 LED