の続きです。
前回まででRaspberry pi 2のFreeBSDの設定は、ハード・ソフトともに終了しました。
最後は、時計のプログラムを書いて終了です。
はじめはSPIを使って制御しようと思ったのですが、1つしかないSPIを使うのは勿体無いので、GPIOを4つ使うことにしました。
GPIOの制御はgpioctlを使ってもできるのですが、シェルスクリプトで時計を書くのはちょっと面倒なので、C言語で書くことにします。
C言語でのGPIOの制御の仕方は、gpio(3)のmanを見ると良いと思います。
サンプルコードはこんな感じです。
コンパイルには、libgpio.hとgpio.cが必要です。
FreeBSDのソースツリーから持ってくるか、以下から入手してください。
clock.c
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include "libgpio.h"
#define CLOCK_PIN_MOSI (17)
#define CLOCK_PIN_SCLK (27)
#define CLOCK_PIN_LATCH (23)
#define CLOCK_PIN_BLINK (24)
#define CLOCK_INTERRUPTION (20)
unsigned char iTable[256];
void CLOCK_initTable(void)
{
for(int tCount1=0;tCount1<256;tCount1++)
{
iTable[tCount1]=0x00;
}
iTable['0']=0x3f;
iTable['1']=0x06;
iTable['2']=0x5b;
iTable['3']=0x4f;
iTable['4']=0x66;
iTable['5']=0x6d;
iTable['6']=0x7d;
iTable['7']=0x27;
iTable['8']=0x7f;
iTable['9']=0x6f;
iTable['C']=0x39;
iTable['E']=0x79;
iTable['G']=0x3d;
iTable['H']=0x76;
iTable['I']=0x06;
iTable['J']=0x1e;
iTable['L']=0x38;
iTable['O']=0x3f;
iTable['P']=0x73;
iTable['T']=0x31;
iTable['U']=0x3e;
iTable['Y']=0x66;
iTable['a']=0x77;
iTable['b']=0x7c;
iTable['c']=0x58;
iTable['d']=0x5e;
iTable['e']=0x7b;
iTable['f']=0x71;
iTable['g']=0x6f;
iTable['h']=0x74;
iTable['i']=0x05;
iTable['j']=0x0d;
iTable['l']=0x18;
iTable['n']=0x54;
iTable['o']=0x5c;
iTable['p']=0x73;
iTable['q']=0x67;
iTable['r']=0x50;
iTable['s']=0x6d;
iTable['t']=0x78;
iTable['u']=0x1c;
iTable['y']=0x6e;
iTable['=']=0x09;
iTable['-']=0x40;
}
void CLOCK_sendChar(gpio_handle_t aHandle,unsigned char aChar)
{
for(int tCount1=0;tCount1<8;tCount1++)
{
gpio_pin_low(aHandle,CLOCK_PIN_SCLK);
if(iTable[aChar]&(0x80>>tCount1))
{
gpio_pin_high(aHandle,CLOCK_PIN_MOSI);
}
else
{
gpio_pin_low(aHandle,CLOCK_PIN_MOSI);
}
gpio_pin_high(aHandle,CLOCK_PIN_SCLK);
}
}
void CLOCK_reflect(gpio_handle_t aHandle)
{
gpio_pin_high(aHandle,CLOCK_PIN_LATCH);
gpio_pin_low(aHandle,CLOCK_PIN_LATCH);
}
volatile sig_atomic_t iEFlag=0;
void signal_handler(int aSig, siginfo_t *aInfo, void *aCtx)
{
iEFlag=1;
}
int main(void)
{
gpio_handle_t tHandle;
char tDateString[64];
char tDateSecond;
time_t tEpocMinites;
struct timeval tCurrentTime;
int tToggleCount;
long tInterruption;
struct sigaction tSASigAbrt,tSASigTerm;
memset(&tSASigAbrt,0,sizeof(tSASigAbrt));
memset(&tSASigTerm,0,sizeof(tSASigTerm));
tSASigAbrt.sa_sigaction=signal_handler;
tSASigAbrt.sa_flags=SA_SIGINFO;
tSASigTerm.sa_sigaction=signal_handler;
tSASigTerm.sa_flags=SA_SIGINFO;
if(sigaction(SIGINT,&tSASigAbrt,NULL)<0)
{
exit(1);
}
if(sigaction(SIGTERM,&tSASigTerm,NULL)<0)
{
exit(1);
}
CLOCK_initTable();
tHandle=gpio_open(0);
gpio_pin_output(tHandle,CLOCK_PIN_MOSI);
gpio_pin_output(tHandle,CLOCK_PIN_SCLK);
gpio_pin_output(tHandle,CLOCK_PIN_LATCH);
gpio_pin_output(tHandle,CLOCK_PIN_BLINK);
gpio_pin_low(tHandle,CLOCK_PIN_MOSI);
gpio_pin_low(tHandle,CLOCK_PIN_SCLK);
gpio_pin_low(tHandle,CLOCK_PIN_LATCH);
gpio_pin_low(tHandle,CLOCK_PIN_BLINK);
tInterruption=(1000000/CLOCK_INTERRUPTION);
tToggleCount=0;
tDateSecond=0x00;
while(1)
{
gettimeofday(&tCurrentTime,NULL);
tEpocMinites=(time_t)tCurrentTime.tv_sec;
strftime(tDateString,sizeof(tDateString),"%H%M%S",localtime(&tEpocMinites));
if(tDateSecond!=tDateString[5])
{
tDateSecond=tDateString[5];
if(tDateString[0]=='0')
{
tDateString[0]=0x00;
}
for(int tCount1=0;tCount1<6;tCount1++)
{
CLOCK_sendChar(tHandle,tDateString[tCount1]);
}
CLOCK_reflect(tHandle);
gpio_pin_high(tHandle,CLOCK_PIN_BLINK);
tToggleCount=0;
}
if(tToggleCount==(CLOCK_INTERRUPTION/2))
{
gpio_pin_low(tHandle,CLOCK_PIN_BLINK);
}
tToggleCount++;
usleep(tInterruption);
if(iEFlag)
{
for(int tCount1=0;tCount1<6;tCount1++)
{
CLOCK_sendChar(tHandle,0x00);
}
CLOCK_reflect(tHandle);
gpio_pin_low(tHandle,CLOCK_PIN_MOSI);
gpio_pin_low(tHandle,CLOCK_PIN_SCLK);
gpio_pin_low(tHandle,CLOCK_PIN_LATCH);
gpio_pin_low(tHandle,CLOCK_PIN_BLINK);
gpio_close(tHandle);
exit(1);
}
}
gpio_close(tHandle);
return 0;
}
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include "libgpio.h"
#define CLOCK_PIN_MOSI (17)
#define CLOCK_PIN_SCLK (27)
#define CLOCK_PIN_LATCH (23)
#define CLOCK_PIN_BLINK (24)
#define CLOCK_INTERRUPTION (20)
unsigned char iTable[256];
void CLOCK_initTable(void)
{
for(int tCount1=0;tCount1<256;tCount1++)
{
iTable[tCount1]=0x00;
}
iTable['0']=0x3f;
iTable['1']=0x06;
iTable['2']=0x5b;
iTable['3']=0x4f;
iTable['4']=0x66;
iTable['5']=0x6d;
iTable['6']=0x7d;
iTable['7']=0x27;
iTable['8']=0x7f;
iTable['9']=0x6f;
iTable['C']=0x39;
iTable['E']=0x79;
iTable['G']=0x3d;
iTable['H']=0x76;
iTable['I']=0x06;
iTable['J']=0x1e;
iTable['L']=0x38;
iTable['O']=0x3f;
iTable['P']=0x73;
iTable['T']=0x31;
iTable['U']=0x3e;
iTable['Y']=0x66;
iTable['a']=0x77;
iTable['b']=0x7c;
iTable['c']=0x58;
iTable['d']=0x5e;
iTable['e']=0x7b;
iTable['f']=0x71;
iTable['g']=0x6f;
iTable['h']=0x74;
iTable['i']=0x05;
iTable['j']=0x0d;
iTable['l']=0x18;
iTable['n']=0x54;
iTable['o']=0x5c;
iTable['p']=0x73;
iTable['q']=0x67;
iTable['r']=0x50;
iTable['s']=0x6d;
iTable['t']=0x78;
iTable['u']=0x1c;
iTable['y']=0x6e;
iTable['=']=0x09;
iTable['-']=0x40;
}
void CLOCK_sendChar(gpio_handle_t aHandle,unsigned char aChar)
{
for(int tCount1=0;tCount1<8;tCount1++)
{
gpio_pin_low(aHandle,CLOCK_PIN_SCLK);
if(iTable[aChar]&(0x80>>tCount1))
{
gpio_pin_high(aHandle,CLOCK_PIN_MOSI);
}
else
{
gpio_pin_low(aHandle,CLOCK_PIN_MOSI);
}
gpio_pin_high(aHandle,CLOCK_PIN_SCLK);
}
}
void CLOCK_reflect(gpio_handle_t aHandle)
{
gpio_pin_high(aHandle,CLOCK_PIN_LATCH);
gpio_pin_low(aHandle,CLOCK_PIN_LATCH);
}
volatile sig_atomic_t iEFlag=0;
void signal_handler(int aSig, siginfo_t *aInfo, void *aCtx)
{
iEFlag=1;
}
int main(void)
{
gpio_handle_t tHandle;
char tDateString[64];
char tDateSecond;
time_t tEpocMinites;
struct timeval tCurrentTime;
int tToggleCount;
long tInterruption;
struct sigaction tSASigAbrt,tSASigTerm;
memset(&tSASigAbrt,0,sizeof(tSASigAbrt));
memset(&tSASigTerm,0,sizeof(tSASigTerm));
tSASigAbrt.sa_sigaction=signal_handler;
tSASigAbrt.sa_flags=SA_SIGINFO;
tSASigTerm.sa_sigaction=signal_handler;
tSASigTerm.sa_flags=SA_SIGINFO;
if(sigaction(SIGINT,&tSASigAbrt,NULL)<0)
{
exit(1);
}
if(sigaction(SIGTERM,&tSASigTerm,NULL)<0)
{
exit(1);
}
CLOCK_initTable();
tHandle=gpio_open(0);
gpio_pin_output(tHandle,CLOCK_PIN_MOSI);
gpio_pin_output(tHandle,CLOCK_PIN_SCLK);
gpio_pin_output(tHandle,CLOCK_PIN_LATCH);
gpio_pin_output(tHandle,CLOCK_PIN_BLINK);
gpio_pin_low(tHandle,CLOCK_PIN_MOSI);
gpio_pin_low(tHandle,CLOCK_PIN_SCLK);
gpio_pin_low(tHandle,CLOCK_PIN_LATCH);
gpio_pin_low(tHandle,CLOCK_PIN_BLINK);
tInterruption=(1000000/CLOCK_INTERRUPTION);
tToggleCount=0;
tDateSecond=0x00;
while(1)
{
gettimeofday(&tCurrentTime,NULL);
tEpocMinites=(time_t)tCurrentTime.tv_sec;
strftime(tDateString,sizeof(tDateString),"%H%M%S",localtime(&tEpocMinites));
if(tDateSecond!=tDateString[5])
{
tDateSecond=tDateString[5];
if(tDateString[0]=='0')
{
tDateString[0]=0x00;
}
for(int tCount1=0;tCount1<6;tCount1++)
{
CLOCK_sendChar(tHandle,tDateString[tCount1]);
}
CLOCK_reflect(tHandle);
gpio_pin_high(tHandle,CLOCK_PIN_BLINK);
tToggleCount=0;
}
if(tToggleCount==(CLOCK_INTERRUPTION/2))
{
gpio_pin_low(tHandle,CLOCK_PIN_BLINK);
}
tToggleCount++;
usleep(tInterruption);
if(iEFlag)
{
for(int tCount1=0;tCount1<6;tCount1++)
{
CLOCK_sendChar(tHandle,0x00);
}
CLOCK_reflect(tHandle);
gpio_pin_low(tHandle,CLOCK_PIN_MOSI);
gpio_pin_low(tHandle,CLOCK_PIN_SCLK);
gpio_pin_low(tHandle,CLOCK_PIN_LATCH);
gpio_pin_low(tHandle,CLOCK_PIN_BLINK);
gpio_close(tHandle);
exit(1);
}
}
gpio_close(tHandle);
return 0;
}
冒頭のdefineで設定しているのは、GPIOのピン番号です。
物理ピン番号ではなく、論理ピン番号(=BCMピン番号)ですので注意してください。
冒頭に制作したLED時計との接続は、以下の通りです。
Vcc ---- 物理ピン 4番
SDI ---- 物理ピン11番(GPIO 17)
CLK ---- 物理ピン13番(GPIO 27)
BLK ---- 物理ピン16番(GPIO 23)
LATCH ---- 物理ピン18番(GPIO 24)
GND ---- 物理ピン 6番
このプログラムでは、論理ピン番号17、27のGPIOで、SPIをエミュレートしています。
大したことをしていないプログラムですので、読めばわかると思いますが、比較的わかりにくい部分だけ解説すると、
です。
iTable 7セグLED用のフォントデータ
CLOCK_sendChar CLKに8クロックを出力して1文字分のコードを送る関数
CLOCK_reflect LATCHに立ち上がりクロックを出力して、シフトレジスタに蓄積された文字を7セグLEDに反映させる関数
CLOCK_sendChar CLKに8クロックを出力して1文字分のコードを送る関数
CLOCK_reflect LATCHに立ち上がりクロックを出力して、シフトレジスタに蓄積された文字を7セグLEDに反映させる関数
です。
mainでは、1/CLOCK_INTERRUPTION秒毎に現在の時間を取得し、前回の取得時から1秒進んでいた場合に、時計の再描画を掛けています。
やる気のないビルド用スクリプトもつけておきますので、これを使ってビルドしてください。
build.sh
#!/bin/sh
rm *.o
cc -c gpio.c
cc -c main.c
cc -o clock gpio.o main.o
rm *.o
cc -c gpio.c
cc -c main.c
cc -o clock gpio.o main.o
特に問題なければ、clockという実行ファイルができるので、これを実行すれば7セグLED時計は動作するはずです。
0 件のコメント:
コメントを投稿