Skip to content

Instantly share code, notes, and snippets.

@recuraki
Last active March 13, 2021 15:22
Show Gist options
  • Save recuraki/edfe8bc22c05cbf99705f39c4da877b6 to your computer and use it in GitHub Desktop.
Save recuraki/edfe8bc22c05cbf99705f39c4da877b6 to your computer and use it in GitHub Desktop.
HP5082を制御します。
// 本コードの
// 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