ATmega328PBを使う (4) SPIでマイコン内蔵RGB LEDを点ける
初めに
LEDをPWMで点灯させると明るさは調整できますが色見は調整できません。プラモデルを電飾する場合は、色見の調整を行いたい場合があります。RGBそれぞれのLEDの明るさを調整して色を作ることができます。マイコン内蔵RGB LEDであれば個々のLEDをPWMで明るさ調整する必要がありません。
作例はこちら
https://www.youtube.com/watch?v=kqoh1bq-qb4
マイコン内蔵RGB LED
マイコン内蔵RGB LEDは色々ありますが、ここでは秋月電子で販売しているsk6812-mini,SK6812 SIDEを対象にします。
制御に使う信号はデータのみで、複数個をカスケードに接続できます。
このLEDは、RESET後に最初に受信した24bitのデータでLEDを点灯し、それ以降のデータはDOから出力します。色を変える場合はRESETを送ってからデータを送ることになるため、接続するLEDの数で更新周期に制約が出てきます。
制御フォーマット/タイミング
1bitの通信タイミングは以下の通りです。
周期の最大値が規定されていないことから、H/Lの期間の比率でビットの判定をしているのではなく’H'の期間で判定していると思われます。
立上りから0.4us以内であれば'0'、1.0usであれば'1'となります。
制御方法
ソフト制御で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データを送信し、データ送信中であればデータ送信を行います。送信データ数により終了判断を行います。
おわり
Author And Source
この問題について(ATmega328PBを使う (4) SPIでマイコン内蔵RGB LEDを点ける), 我々は、より多くの情報をここで見つけました https://qiita.com/toshidln/items/e110e64b2b3a5d9f1bd9著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .