Last active
March 13, 2021 15:22
-
-
Save recuraki/edfe8bc22c05cbf99705f39c4da877b6 to your computer and use it in GitHub Desktop.
HP5082を制御します。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 本コードの | |
// I2C部分は中尾 司様の以下コードを参考にしています | |
// http://www.eleki-jack.com/mycom2/2007/12/avri2c8twii2c_4.html#more | |
// 07/11/15 www.wsnak.com T.Nakao | |
// また、nora66さんのコメントを参考にしています。 | |
// http://nora66.com/avr/prog2.html | |
// タイマーコード部分はsim00様の以下のコードを参考にしています | |
// http://blog.goo.ne.jp/sim00/e/1ab8d1564106581d1168edc059042c30 | |
#define F_CPU 8000000 | |
#include <stdio.h> | |
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
#include <avr/eeprom.h> | |
#include <util/delay.h> | |
//i2cの各種制御ではunsignedのキーワードを使う。typedefしておく。 | |
typedef unsigned char BYTE; | |
typedef unsigned short WORD; | |
/* HP5082-7441を制御します。 | |
ATmega328 | |
I2C | |
信号ライン | |
PC4(SDA/27) | |
PC5(SCL/28) | |
ピンコネ: | |
1: GND(カソード) 1 PD0(2) | |
3: GND(カソード) 2 PD1(3) | |
5: GND(カソード) 3 PD2(4) | |
7: GND(カソード) 4 PD3(5) | |
9: GND(カソード) 5 PD4(6) | |
11: GND(カソード) 6PD5(11) | |
13: GND(カソード) 7PD6(12 | |
15: GND(カソード) 8PD7(13 | |
17: GND(カソード) 9PB0(14) | |
6: a PC0(23) | |
14:b PC1(24) | |
2: c PC2(25) | |
10:d PC3(26) | |
8:e PB1(15) | |
16:f PB2(16) | |
12:g PB6(9) | |
4:h PB7(10) | |
セグメントの位置 | |
A | |
- | |
F| |B | |
- <- G | |
E| |C | |
- . <- H | |
D | |
I2Cの仕様 | |
Writeで連続した文字列として9桁分のデータを送ります。 | |
必要があるなら、 | |
Writeの連続データは最初の1桁をアドレスですが、これはデータの1桁目になります。つまり、 | |
012345678と表示させるには、 | |
shellなら | |
sudo i2cset -y 1 0x11 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 i | |
sudo i2cset -y 1 0x11 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 i | |
Pythonの場合 | |
import smbus | |
import time | |
import random | |
i2c = smbus.SMBus(1) | |
addr = 0x11 | |
while True: | |
display = [random.randint(0,9) for _ in range(9)] | |
i2c.write_i2c_block_data(addr, display[0], display[1:]) | |
time.sleep(0.05) | |
import smbus | |
import datetime | |
import time | |
import random | |
i2c = smbus.SMBus(1) | |
addr = 0x11 | |
display = [0x12] * 9 | |
display[8] = 0x13 | |
while True: | |
timelist = str(datetime.datetime.today()).split(" ")[1].split(".")[0].split(":") | |
print(timelist) | |
display[0] = ord(timelist[0][0]) - 0x30 | |
display[1] = ord(timelist[0][1]) - 0x30 | |
display[3] = ord(timelist[1][0]) - 0x30 | |
display[4] = ord(timelist[1][1]) - 0x30 | |
display[6] = ord(timelist[2][0]) - 0x30 | |
display[7] = ord(timelist[2][1]) - 0x30 | |
i2c.write_i2c_block_data(addr, display[0], display[1:]) | |
time.sleep(1) | |
*/ | |
#define rgTWISlEna (1<<TWEA)|(1<<TWEN) // スレーブ ACK応答 | |
#define rgClrTWInt rgTWISlEna|(1<<TWINT) // TWINT割り込み要因フラグのクリア | |
BYTE Phase; // 受信フェーズ | |
BYTE MyAdrs; // My I2Cアドレス | |
BYTE CByte; // 受信したコントロール・バイト | |
BYTE I2CData; | |
void I2CSlInit(BYTE adrs); | |
void I2CSlCom(); | |
void SlaveInit(BYTE dat); | |
void SlaveReceive(BYTE dat); | |
BYTE SlaveSend(void); | |
// digitに関してはカソードなので、0にするのがON | |
#define digit0Bit 0 | |
#define digit0PORT PORTD | |
#define digit1Bit 1 | |
#define digit1PORT PORTD | |
#define digit2Bit 2 | |
#define digit2PORT PORTD | |
#define digit3Bit 3 | |
#define digit3PORT PORTD | |
#define digit4Bit 4 | |
#define digit4PORT PORTD | |
#define digit5Bit 5 | |
#define digit5PORT PORTD | |
#define digit6Bit 6 | |
#define digit6PORT PORTD | |
#define digit7Bit 7 | |
#define digit7PORT PORTD | |
#define digit8Bit 0 | |
#define digit8PORT PORTB | |
#define DIGIT0_OFF digit0PORT |= (1<<digit0Bit) | |
#define DIGIT0_ON digit0PORT &=~(1<<digit0Bit) | |
#define DIGIT1_OFF digit1PORT |= (1<<digit1Bit) | |
#define DIGIT1_ON digit1PORT &=~(1<<digit1Bit) | |
#define DIGIT2_OFF digit2PORT |= (1<<digit2Bit) | |
#define DIGIT2_ON digit2PORT &=~(1<<digit2Bit) | |
#define DIGIT3_OFF digit3PORT |= (1<<digit3Bit) | |
#define DIGIT3_ON digit3PORT &=~(1<<digit3Bit) | |
#define DIGIT4_OFF digit4PORT |= (1<<digit4Bit) | |
#define DIGIT4_ON digit4PORT &=~(1<<digit4Bit) | |
#define DIGIT5_OFF digit5PORT |= (1<<digit5Bit) | |
#define DIGIT5_ON digit5PORT &=~(1<<digit5Bit) | |
#define DIGIT6_OFF digit6PORT |= (1<<digit6Bit) | |
#define DIGIT6_ON digit6PORT &=~(1<<digit6Bit) | |
#define DIGIT7_OFF digit7PORT |= (1<<digit7Bit) | |
#define DIGIT7_ON digit7PORT &=~(1<<digit7Bit) | |
#define DIGIT8_OFF digit8PORT |= (1<<digit8Bit) | |
#define DIGIT8_ON digit8PORT &=~(1<<digit8Bit) | |
// セグメント(アノード)側は送るので | |
#define segABit 0 | |
#define segAPORT PORTC | |
#define segBBit 1 | |
#define segBPORT PORTC | |
#define segCBit 2 | |
#define segCPORT PORTC | |
#define segDBit 3 | |
#define segDPORT PORTC | |
#define segEBit 1 | |
#define segEPORT PORTB | |
#define segFBit 2 | |
#define segFPORT PORTB | |
#define segGBit 6 | |
#define segGPORT PORTB | |
#define segHBit 7 | |
#define segHPORT PORTB | |
#define SEGA_ON segAPORT |= (1<<segABit) | |
#define SEGA_OFF segAPORT &=~(1<<segABit) | |
#define SEGB_ON segBPORT |= (1<<segBBit) | |
#define SEGB_OFF segBPORT &=~(1<<segBBit) | |
#define SEGC_ON segCPORT |= (1<<segCBit) | |
#define SEGC_OFF segCPORT &=~(1<<segCBit) | |
#define SEGD_ON segDPORT |= (1<<segDBit) | |
#define SEGD_OFF segDPORT &=~(1<<segDBit) | |
#define SEGE_ON segEPORT |= (1<<segEBit) | |
#define SEGE_OFF segEPORT &=~(1<<segEBit) | |
#define SEGF_ON segFPORT |= (1<<segFBit) | |
#define SEGF_OFF segFPORT &=~(1<<segFBit) | |
#define SEGG_ON segGPORT |= (1<<segGBit) | |
#define SEGG_OFF segGPORT &=~(1<<segGBit) | |
#define SEGH_ON segHPORT |= (1<<segHBit) | |
#define SEGH_OFF segHPORT &=~(1<<segHBit) | |
char font[0x14][8] = { | |
//A B C D E F G H | |
{1, 1, 1, 1, 1, 1, 0, 0}, // 0 | |
{0, 1, 1, 0, 0, 0, 0, 0}, // 1 | |
{1, 1, 0, 1, 1, 0, 1, 0}, // 2 | |
{1, 1, 1, 1, 0, 0, 1, 0}, // 3 | |
{0, 1, 1, 0, 0, 1, 1, 0}, // 4 | |
{1, 0, 1, 1, 0, 1, 1, 0}, // 5 | |
{1, 0, 1, 1, 1, 1, 1, 0}, // 6 | |
{1, 1, 1, 0, 0, 1, 0, 0}, // 7 | |
{1, 1, 1, 1, 1, 1, 1, 0}, // 8 | |
{1, 1, 1, 1, 0, 1, 1, 0}, // 9 | |
{1, 1, 1, 0, 1, 1, 1, 0}, // A | |
{0, 0, 1, 1, 1, 1, 1, 0}, // b | |
{1, 0, 0, 1, 1, 1, 0, 0}, // C | |
{0, 1, 1, 1, 1, 0, 1, 0}, // d | |
{1, 0, 0, 1, 1, 1, 1, 0}, // E | |
{1, 0, 0, 0, 1, 1, 1, 0}, // F | |
{0, 0, 0, 0, 0, 0, 0, 1}, // . (0x10 | |
{0, 0, 0, 1, 0, 0, 0, 0}, // _ (0x11) | |
{0, 0, 0, 0, 0, 0, 1, 0}, // - (0x12) | |
{0, 0, 0, 0, 0, 0, 0, 0}, // NULL (0x13) | |
}; | |
void setAnode(int value){ | |
if(font[value][0]==1) {SEGA_ON;} else {SEGA_OFF;} | |
if(font[value][1]==1) {SEGB_ON;} else {SEGB_OFF;} | |
if(font[value][2]==1) {SEGC_ON;} else {SEGC_OFF;} | |
if(font[value][3]==1) {SEGD_ON;} else {SEGD_OFF;} | |
if(font[value][4]==1) {SEGE_ON;} else {SEGE_OFF;} | |
if(font[value][5]==1) {SEGF_ON;} else {SEGF_OFF;} | |
if(font[value][6]==1) {SEGG_ON;} else {SEGG_OFF;} | |
if(font[value][7]==1) {SEGH_ON;} else {SEGH_OFF;} | |
} | |
char display[9] = {0, 1,2,3,4,5,6,7,8}; | |
char randtable[100] ={ | |
1,4,2,3,5,7,6,8,9,0, | |
1,4,5,7,3,6,8,8,3,0, | |
1,4,5,7,3,6,8,8,3,0, | |
1,2,3,4,6,7,3,2,4,6, | |
1,4,2,3,5,7,6,8,9,0, | |
1,4,5,7,3,6,8,8,3,0, | |
1,4,5,7,3,6,8,8,3,0, | |
1,2,3,4,6,7,3,2,4,6, | |
1,4,2,3,5,7,6,8,9,0, | |
1,4,5,7,3,6,8,8,3,0, | |
}; | |
int turn = 0; | |
int offset = 0; | |
int cnt = 0; | |
//----------------------------------------------------------- | |
// 割り込み処理ハンドラ | |
ISR(TIMER1_COMPA_vect) { | |
/* | |
++cnt; | |
if(cnt == 50){ | |
cnt = 0; | |
offset += randtable[offset]; | |
if(offset > 80){offset %= 80;} | |
for(int i=0; i < 9; ++i){ | |
display[i] = randtable[offset + i]; | |
} | |
} | |
*/ | |
if(turn == 0) { DIGIT8_OFF; setAnode(display[0]); DIGIT0_ON; } | |
else if(turn == 1) { DIGIT0_OFF; setAnode(display[1]); DIGIT1_ON; } | |
else if(turn == 2) { DIGIT1_OFF; setAnode(display[2]); DIGIT2_ON; } | |
else if(turn == 3) { DIGIT2_OFF; setAnode(display[3]); DIGIT3_ON; } | |
else if(turn == 4) { DIGIT3_OFF; setAnode(display[4]); DIGIT4_ON; } | |
else if(turn == 5) { DIGIT4_OFF; setAnode(display[5]); DIGIT5_ON; } | |
else if(turn == 6) { DIGIT5_OFF; setAnode(display[6]); DIGIT6_ON; } | |
else if(turn == 7) { DIGIT6_OFF; setAnode(display[7]); DIGIT7_ON; } | |
else if(turn == 8) { DIGIT7_OFF; setAnode(display[8]); DIGIT8_ON; } | |
++turn; | |
turn %= 9; | |
} | |
//----------------------------------------------------------- | |
// タイマー初期化 | |
void timer_init(unsigned t) | |
{ | |
// 15.11.5 タイマ/カウンタ1比較レジスタA | |
OCR1A = t; | |
// 15.11.1 タイマ/カウンタ1制御レジスタA (初期値は0x00なので必要ない) | |
// ++-------COM1A1:COM1A0 00 OC1A切断 | |
// ||++---- COM1B1:COM1B0 00 OC1B切断 | |
// |||| ++ WGM11:WGM10 00 波形生成種別(4bitの下位2bit) | |
TCCR1A = 0b00000000; | |
// 15.11.2 タイマ/カウンタ1制御レジスタB | |
// +------- ICNC1 0 | |
// |+------ ICES1 0 | |
// || ++--- WGM13:WGM12 01 波形生成種別(4bitの上位2bit) CTC top=OCR1A | |
// || ||+++ CS12:CS11:CS10 101 1024分周 | |
TCCR1B = 0b00001101; | |
// 15.11.8 タイマ/カウンタ1割り込みマスクレジスタ | |
// +----- ICIE1 0 | |
// | +-- OCIE1B 0 | |
// | |+- OCIE1A 1 タイマ/カウンタ1比較A割り込み許可 | |
// | ||+ TOIE1 0 | |
TIMSK1 = 0b00000010; | |
sei(); // 割り込み許可 | |
} | |
int main(){ | |
uint8_t result; | |
eeprom_busy_wait(); // eepromがreadできるまで待つ | |
result = eeprom_read_byte(0x0000); // メモリの0x00を自分のスレーブに仕様とします。 | |
MyAdrs = result; // 自I2Cスレーブ・アドレス | |
if(MyAdrs > 0x77 || MyAdrs < 0x03) // 禁止されているaddress | |
{ | |
MyAdrs = 0x20; // 自I2Cスレーブ・アドレス(仮) | |
} | |
timer_init(1); // 10 * 1024us毎に割り込み (約50Hz) @ 1MHz | |
// LED用ポートを出力に設定 | |
// PORT PDはすべて出力ポート | |
// PORT PCはLSB側だけ | |
DDRD = 0b11111111; | |
DDRB = 0b11000111; | |
DDRC = 0b00001111; | |
PORTD = 0b00000000; | |
PORTB = 0b00000000; | |
PORTC = 0b00000000; | |
I2CSlInit(MyAdrs); // I2Cスレーブ初期化 | |
while(1) { | |
I2CSlCom(); | |
} | |
} | |
/* I2Cライブラリの補足(recuraki) | |
I2CSlInit: 気にしなくていい。このまま | |
I2CSlCom: これも気にしなくていい。 | |
まず、このライブラリのSlaveの動きを理解しておく必要がある。 | |
1. Slaveは「自宛の通信が来たときのみ反応」 | |
2. 処理は、SlaveInit -> SlaveReceive -> SlaveSend | |
で呼ばれる。init, sendでは、例えば、sei cliなどを行うのがよいように思える。 | |
*/ | |
// ----------------------------------------------------------- | |
// I2Cスレーブ初期化 | |
// IN adrs:My I2Cスレーブ・アドレス (メモリではない。デバイスとしてのアドレス) | |
// ----------------------------------------------------------- | |
void I2CSlInit(BYTE adrs) { | |
adrs <<= 1; | |
// adrs |= 1; // ジェネラル・コール・アドレス許可 | |
TWAR = adrs; | |
TWCR = rgTWISlEna; | |
} | |
// ----------------------------------------------------------- | |
// I2Cスレーブ処理(メイン・ループに入れる) | |
// ----------------------------------------------------------- | |
void I2CSlCom() | |
{ | |
if(!(TWCR & (1<<TWINT))) return; // TWINTが未セットのとき終了 | |
cli(); | |
// TWINTがセットされているとき | |
switch(TWSR) { // TWSR=状態コード | |
//---------------------------- | |
// データ受取 | |
//---------------------------- | |
// CB(Write)受信 | |
case 0x60: | |
SlaveInit(TWDR); // データ受取のシーケンス開始処理(TWDR=CB) | |
TWCR = rgClrTWInt; // INT要求フラグ・クリア | |
break; | |
// data受信 | |
case 0x80: | |
SlaveReceive(TWDR); // データ受取処理(TWDR=data) | |
TWCR = rgClrTWInt; // INT要求フラグ・クリア | |
break; | |
//---------------------------- | |
// データ送出 | |
//---------------------------- | |
// CB(Read)受信 | |
case 0xA8: | |
SlaveInit(TWDR); // データ送出のシーケンス開始処理(TWDR=CB) | |
TWDR = SlaveSend(); // 第1バイト送出 | |
TWCR = rgClrTWInt; // INT要求フラグ・クリア | |
break; | |
// ACK受信 | |
case 0xB8: | |
TWDR = SlaveSend(); // 第2バイト以降送出(送出継続) | |
TWCR = rgClrTWInt; // INT要求フラグ・クリア | |
break; | |
//---------------------------- | |
// その他 | |
//---------------------------- | |
case 0xC0: // NOACK受信(最終データなのでスレーブ送信終了) | |
case 0xA0: // スレーブ受信中にストップ・コンディションが来た | |
TWCR = rgClrTWInt; // INT要求フラグ・クリア | |
break; | |
} | |
sei(); | |
} | |
BYTE sessionAddr; | |
//--------------------------------------------------------------------------------- | |
// CB受信イベント・ハンドラ | |
// IN dat: 受信したデータ(コントロール・バイト) | |
// このハンドラでは、コントロール・バイトを受信したタイミング、つまり、通信パケットの送受信の始まりの | |
// タイミングを知ることができます。用途としては、たとえば、送受信バッファのポインタを0に初期化するとか | |
// 送受信のバイト数のカウンタを0にリセットするなどのパケット単位の処理の初期化に使います。 | |
//--------------------------------------------------------------------------------- | |
void SlaveInit(BYTE dat) | |
{ | |
sessionAddr = 0; | |
} | |
//--------------------------------------------------------------------------------- | |
// スレーブ受信イベント・ハンドラ | |
// IN dat: 受信したデータ | |
// このハンドラでは、データを受信したタイミングと、受信データを得ることができます。受信データをバッファ | |
// に格納するなどの処理はこのハンドラで行います。 | |
//--------------------------------------------------------------------------------- | |
void SlaveReceive(BYTE dat) | |
{ | |
I2CData = dat; | |
display[sessionAddr] = dat; | |
++sessionAddr; | |
} | |
//--------------------------------------------------------------------------------- | |
// スレーブ送信イベント・ハンドラ | |
// OUT Acc: 送信するデータ | |
// このハンドラは、スレーブ送信直前に呼び出されるため、送信バッファからデータを取り出すなどの処理は | |
// ここで行います。 | |
//--------------------------------------------------------------------------------- | |
BYTE SlaveSend(void) | |
{ | |
return I2CData; // 過去にマスタから送られてきたデータを送り返す | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment