ATmega328PB 사용 (4) SPI로 마이크로 컴퓨터 내장 RGB LED를 켜기

처음에



LED를 PWM으로 켜면 밝기를 조정할 수 있지만 색조는 조정할 수 없습니다. 프라모델을 전장하는 경우는, 색견의 조정을 실시하고 싶은 경우가 있습니다. RGB 각 LED의 밝기를 조정하여 색상을 만들 수 있습니다. 마이크로 컴퓨터 내장 RGB LED라면 개별 LED를 PWM으로 밝기 조정할 필요가 없습니다.

작례는 이쪽
htps //w w. 요츠베. 이 m/와 tch? v = k ぉ h1bq-qb4

마이크로 컴퓨터 내장 RGB LED



마이크로 컴퓨터 내장 RGB LED는 여러 가지가 있습니다만, 여기에서는 아키즈키 전자에서 판매하고 있는 sk6812-mini, SK6812 SIDE를 대상으로 합니다.
제어에 사용하는 신호는 데이터만으로 여러 개를 캐스케이드에 연결할 수 있습니다.


이 LED는 RESET 후에 처음 수신한 24비트 데이터로 LED를 켜고 이후 데이터는 DO에서 출력합니다. 색을 바꾸는 경우는 RESET을 보내고 나서 데이터를 보내게 되므로, 접속하는 LED의 수로 갱신 주기에 제약이 나옵니다.


제어 포맷/타이밍



1bit의 통신 타이밍은 다음과 같습니다.


주기의 최대치가 규정되어 있지 않기 때문에, H/L의 기간의 비율로 비트의 판정을 하고 있는 것이 아니라 'H'의 기간으로 판정하고 있다고 생각됩니다.
상승에서 0.4us 이내이면 '0', 1.0us이면 '1'이 됩니다.

데이터는 MSB에서 GRB 순으로 전송됩니다.


제어 방법



소프트 제어로 1us 이하의 타이밍을 만들려면 처리를 점유시켜야 합니다. 또한 송신 중에는 인터럽트 등으로 중단시킬 수 없습니다. 그렇다면 사용하기 어려우므로 SPI를 사용하여 구현합니다.
1bit의 데이터 전송 기간을 1byte에 할당하여 H 펄스를 생성합니다.
1bit의 길이는 Min1.2us이므로 이 값을 바탕으로 SPI의 클럭을 결정합니다.
1.2us/8=0.15us
클락으로 하면 6.67MHz가 됩니다만, 이번 사용하는 ATmega328PB_Xplained_Mini의 클락은 16MHz이므로 이 클락은 만들 수 없습니다. 가까운 값으로 16MHz를 2분주한 8MHz로 합니다.
T0H의 길이는 2bit 폭으로 0.25us, T1H의 길이는 5bit 폭으로 0.625us로 합니다.

SPI가 전송하지 않은 기간의 출력은 'L'이므로 외부에서 HC04 등의 인버터로 반전시킵니다.

SPI



구성 요소 설정




클록은 16MHz를 2분주로 하고, Master 모드로 합니다.
포트가 4개 할당되지만 MOSI만 사용합니다.

처리



10ms마다 전송합니다.
절차
1 RGB 데이터에서 전송 데이터 생성
2 Reset 보내기
3 LED 수분 데이터 전송

RGB 데이터에서 전송 데이터 생성


#define RGB_LED_TRAN_NUM    (24)            /* RG  LED 1個当たりのデータ転送数 */
#define RGB_LED_L_DATA      (0b00111111)
#define RGB_LED_H_DATA      (0b00000111)
#define RGB_LED_RESET_LENGTH    (10)        /* Resetデータ長 */
#define RGB_CONV_COUNT      (8)

typedef enum {
    td_State_Reset = 0,
    td_State_Transfer,
    td_State_Idle,
} td_State;


static uint8_t grb[RGB_LED_MAX_NUM][RGB_COLOR_NUM];             /* RGB data */
static uint8_t sdLedData[RGB_LED_MAX_NUM * RGB_LED_TRAN_NUM];   /* SPI送信データ */
static td_State rgbLed_State;                                   /* 制御状態 */

static uint16_t rstTranCount;                   /* reset送信データ数 */
static uint8_t rgbLedTranCount;                 /* RGB LEDデータ数 */
static uint8_t rgbLedNumOfTran;                 /* RGB LED転送数 */
static uint8_t rgbLedLenNum;                    /* RGB LED数 */

static const uint8_t rgbLedResetData = 0xFF;    /* Reset Data */

/* RGB LED転送開始 */
/* 転送データ作成 */
/* 送信開始 */
void rgbLed_start(void)
{
    /* RGB LED転送データ作成 */
    rgbLed_makeSendData();
    /* SPIデータ送信開始 */
    rgbLed_StartTran(); 

}

/* RGBデータから送信データを作成 */
static void rgbLed_makeSendData(void)
{
    uint8_t bitMask;
    uint8_t rgbData;
    uint8_t sendData;
    uint8_t sdPt;

    sdPt = 0;
    for (uint8_t ledNo = 0; ledNo < rgbLedLenNum; ledNo++) {                    /* LED数繰り返し */
        for (uint8_t rgbNo = 0; rgbNo < RGB_COLOR_NUM; rgbNo++) {               /* RGB分繰り返し */
            bitMask = 0b10000000;
            rgbData = grb[ledNo][rgbNo];
            for (uint8_t cnvCount = 0; cnvCount < RGB_CONV_COUNT; cnvCount++) { /* 8bit繰り返し */
                sendData = 0x00;
                if ((rgbData & bitMask) != 0x00) {
                    sendData = RGB_LED_H_DATA;
                } else {
                    sendData = RGB_LED_L_DATA;
                }
                sdLedData[sdPt] = sendData;
                bitMask = bitMask >> 1;
                sdPt++;
            }
        }
    }
}

rgbLed_start 함수는 전송 데이터를 작성한 후 SPI 전송을 시작합니다.
rgbLed_makeSendData 에서는, 색 데이터의 grb[][]의 내용을 1bit마다 체크해, 1byte의 전송 데이터로 변환합니다. 그것을 전송 버퍼의 sdLedData[]에 저장합니다.

송신 처리


/* RGB LED送信開始処理 */
static void rgbLed_StartTran(void)
{
    rgbLed_State = td_State_Reset;
    rstTranCount = 0;
    SPI_MS_Transmit(rgbLedResetData);   /* transmit Reset Data */
}

/* SPI割り込み */
void rgbLed_spi_intr(void)
{
    switch (rgbLed_State)
    {
        case td_State_Reset:        /* Reset出力中 */
            if (rstTranCount > RGB_LED_RESET_LENGTH) {
                /* データ送信開始処理 */
                rgbLed_StartDataTran();
            } else {
                /* Reset送信処理 */
                rgbLed_ResetTran();
            }
            break;
        case td_State_Transfer:     /* データ送信処理 */
            rgbLed_DataTran();
            if (rgbLedTranCount >= rgbLedNumOfTran) {
                /* 送信終了 */
                rgbLedTranCount = 0;
                rgbLed_State = td_State_Idle;
            }
            break;
        default:
            /* 送信完了処理 */
            rgbLed_State = td_State_Idle;
            break;
    }   
}

/* Reset送信処理 */
static void rgbLed_ResetTran(void)
{
    SPI_MS_Transmit(rgbLedResetData);   /* transmit Reset Data */
    rstTranCount++;
}

/* データ送信開始処理 */
static void rgbLed_StartDataTran(void)
{
    rgbLed_State = td_State_Transfer;
    rgbLedTranCount = 0;
    rgbLed_DataTran();
}

/* データ送信処理 */
static void rgbLed_DataTran(void)
{
    SPI_MS_Transmit(sdLedData[rgbLedTranCount]);
    rgbLedTranCount++;
}


rgbLed_StartTran 함수로 전송을 시작합니다.
1byte 전송 종료 후 인터럽트가 발생합니다.
인터럽트 처리에서는 Reset 송신중이면 Reset 데이터를 송신하고, 데이터 송신중이면 데이터 송신을 실시합니다. 송신 데이터 수에 따라 종료 판정을 실시합니다.

좋은 웹페이지 즐겨찾기