今回は秋月電子で販売されている7セグメントLEDドライバ TM1630 を使用してみました。
TM16301つで7セグ5桁または8セグ4桁をダイナミック点灯で制御することができます。※カソードコモンじゃないとダメなので注意
普通に PIC で7セグを制御することも可能ですが、ダイナミック点灯させるのは少々面倒な上にピンも多く必要となるのに対して、TM1630 を使用すると表示データを送信すればよく、ピンも3つで済むのでとても手軽です。
ちなみに TM1630 にはキースキャン機能もあるみたいですが、そちらは使いません。というか何故2つの機能をまとめたのだろうか。
データシートが中国語なので読みづらいですが、Google翻訳の手を借りて読み進めていきました。
まずは通信方式を確認してみます。
SPIのようなシリアル通信ですね。データは送受信可能のようですが、今回は送信だけ使っていきます。
1バイトを送信する関数を作りました。
1 2 3 4 5 6 7 8 |
void TM_Send(char data){ for(char i=0; i<8; i++){ DIO = (data>>i) & 0x1; CLK = 0; CLK = 1; } __delay_us(1); } |
複数バイト送信する場合を想定して1usの遅延(Twait)を入れていて、STBは関数の外で個別に制御することにします。
続いて、データ形式を確認してみます。
ここで、よく分からない点がいくつかあるんですよね。
あと上位ビットを右側に書くのは見づらいからやめてほしい。
そして下の表では SEG14 が B7 に来て SEG8 ~ SEG2 が B6 ~ B0 になってて上の表と違うじゃんか。14の意味する所も気になるがそれは置いといたとしてどっちが正しいのか。
結論から言うと、上の表を信用すればいいようです。
下の図の文中に、”0”を表示させる場合「00Hのアドレスユニットにデータ3FHを書き込むだけでよいことを理解するのは難しくありません。」って書いてあるけど、難しいです。0x3F じゃなくて1つずらして 0x7E を書き込まなくちゃいけませんでした。
…思わず愚痴だらけになってしまいましたがとりあえず動作するのでいいでしょう。
続いて初期化の流れを確認してみます。
なお、データの送信方式は固定アドレスモードとアドレス自動インクリメントモードの2つあるようですが、後者の場合の図です。
Command1:表示モード設定
Command2:データ設定コマンド
Command3:表示アドレス設定
Command4:表示制御コマンド
それぞれのコマンドの詳細はデータシートに書いてありますが、翻訳しなくてもなんとなく雰囲気で分かる所も多いので省略します。
後のサンプルプログラムと比較すれば容易に理解できるかと思います。
というわけで、動作確認してみました。
今回使用した PIC は PIC16F18857 です。7セグLEDはこちらの4桁のものを使用しました。
接続について、K2 ピンはキースキャン用のピンなので未接続です。
また、データシートの接続図には LED の電流制限抵抗は描かれていませんでしたが、過去に何度か抵抗忘れで LED を破壊していて不安なので 100Ω の抵抗を入れておきました。
追記:
輝度の設定を一番低くした状態ですが、電流制限抵抗なしでも壊れずに点灯しました。
通信用の3線にはプルアップ抵抗がついていますが、送信だけの場合なくても大丈夫でした。
100ms 毎にカウントアップするサンプルプログラムです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
#pragma config FEXTOSC = OFF // External Oscillator mode selection bits (Oscillator not enabled) #pragma config RSTOSC = EXT1X // Power-up default value for COSC bits (EXTOSC operating per FEXTOSC bits) #pragma config CLKOUTEN = OFF // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2) #pragma config CSWEN = ON // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed) #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable bit (FSCM timer enabled) #pragma config MCLRE = ON // Master Clear Enable bit (MCLR pin is Master Clear function) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config LPBOREN = OFF // Low-Power BOR enable bit (ULPBOR disabled) #pragma config BOREN = OFF // Brown-out reset enable bits (Brown-out reset disabled) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices) #pragma config ZCD = OFF // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.) #pragma config PPS1WAY = ON // Peripheral Pin Select one-way control (The PPSLOCK bit can be cleared and set only once in software) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset) #pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS) #pragma config WDTE = OFF // WDT operating mode (WDT Disabled, SWDTEN is ignored) #pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required) #pragma config WDTCCS = SC // WDT input clock selector (Software Control) #pragma config WRT = OFF // UserNVM self-write protection bits (Write protection off) #pragma config SCANE = available// Scanner Enable bit (Scanner module is available for use) #pragma config LVP = OFF // Low Voltage Programming Enable bit (High Voltage on MCLR/Vpp must be used for programming) #pragma config CP = OFF // UserNVM Program memory code protection bit (Program Memory code protection disabled) #pragma config CPD = OFF // DataNVM code protection bit (Data EEPROM code protection disabled) #include <xc.h> #define _XTAL_FREQ 4000000 #define STB RC2 #define CLK RC0 #define DIO RC1 const char NUM[11] = { 0b01111110, //0 0b00001100, //1 0b10110110, //2 0b10011110, //3 0b11001100, //4 0b11011010, //5 0b11111010, //6 0b01001110, //7 0b11111110, //8 0b11011110, //9 0b00000000 //void }; void Init(); void TM_Send(char data); void NumToArr(unsigned int n, char* arr); void TM_ShowNum(unsigned int n){ // 0 <= n <= 9999 char arr[4]; NumToArr(n, arr); STB = 0; TM_Send(0xC0); //Set Address for(char i=0; i<4; i++){ TM_Send(NUM[arr[i]]); //Character Data TM_Send(0); //Dummy } STB = 1; } void TM_Init(){ STB = 1; CLK = 1; STB = 0; TM_Send(0x00); //4x8 STB = 1; __delay_us(1); STB = 0; TM_Send(0x40); //Address auto increment STB = 1; __delay_us(1); TM_ShowNum(0); __delay_us(1); STB = 0; TM_Send(0x8F); //Duty 14/16(max) STB = 1; } void main(void) { Init(); TM_Init(); unsigned int count = 0; while(1){ TM_ShowNum(count); count++; __delay_ms(100); } } ///////////////////////////////// void Init(){ ANSELA = 0; TRISA = 0; ANSELB = 0; TRISB = 0; ANSELC = 0; TRISC = 0; } void TM_Send(char data){ for(char i=0; i<8; i++){ DIO = (data>>i) & 0x1; CLK = 0; CLK = 1; } __delay_us(1); } void NumToArr(unsigned int n, char* arr){ for(char i=0; i<4; i++){ //Split n into arr arr[3-i] = n%10; n /= 10; } for(char i=0; i<3; i++){ //Delete initial zero if(arr[i] == 0) arr[i] = 10; //void else break; } } |
7セグを簡単に制御できてなかなかいい感じです。