昨年の秋、MPLAB X + XC8 + MCC環境下で、PIC16F1827を使って、MAX7219使用8桁7セグメントLEDの表示テストをしました。しかし、うまくいきませんでした。
MCCを使うとCONFIGの設定や各設定が格段に楽になるのですが、その分ブラックボックス化され、いざ不具合を見つけようとすると難しくなります。
そこで、今回はMCCを使わないで、XC8だけでテストをしてみます。MAX7219使用8桁7セグメントLEDの表示テストについては、Arduinoで既に行っており(当ブログでの記事はこちら)、今回はそのスケッチをMPLAB Xに移植する形で行いました。
テストした回路図です。PIC16F1827のクロックは、今後周波数カウンタへの発展を考えて、外部クロック(クリスタルオシレータ20MHz)を使っています。
MAX7219のコントロールは、SPIで行います。その時のタイミングチャートです。(MAX7219の説明書より)
CSを1から0にしてデータ転送を開始します。CLKの立ち上がりでDINの値が読み込まれます。8bitデータを送ったらCSを1に戻します。
PIC16G1827でSPIのタイミングを決めるのは、SSPXCON1レジスタとSSPXSTATレジスタです。今回はSSP1を使いますのでX=1とします。
まず、SSP1CON1レジスタの設定です。(必要な部分だけ設定します)
SSP1を有効にするため、SSP1EN=1とします。
クロックの極性は常時Lowでアクティブ時にHighですので、CKP=0とします。
次に、SSP1STATレジスタの設定をします。
クロックエッジCKEは、CKP=0のとき立ち上がりを指定のCKE=1とします。サンプル位置は中央でSMP=0とします。
以上の条件で、PIC16F1827のSPI出力をpico scopeで確認してみました。
SSP1BUF=0x55(0b01010101)として出力しました。
MAX7219のタイミングに合っています。OKです。
テストしたプログラムです。
--------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
// CONFIG1
#pragma config FOSC = ECH //外部クロック
#pragma config WDTE = OFF //ウオッチドックタイマーを使わない
#pragma config PWRTE = ON //パワーアップタイマーON
#pragma config MCLRE = OFF //外部リセット信号は使用しない、
#pragma config CP = OFF //プログラムメモリーを保護しない
#pragma config CPD = OFF //データメモリーを保護しない
#pragma config BOREN = ON //ブラウンアウト リセット 有効
#pragma config CLKOUTEN = OFF //Clock Out OFF
#pragma config IESO = OFF //外部・内部クロックの切替えでの起動はなし
#pragma config FCMEN = OFF //外部クロック監視しない
// CONFIG2
#pragma config WRT = OFF //Flashメモリーを保護しない
#pragma config PLLEN = OFF //PLLを使わない
#pragma config STVREN = ON //スタックがオーバフローやアンダーフローしたらリセットをする
#pragma config BORV = HI //電源電圧降下常時監視電圧(2.5V)設定(HI)
#pragma config LVP = OFF //低電圧プログラミング機能使用しない
#define _XTAL_FREQ 20000000 //クロック20MHz
#define CS LATBbits.LATB3
// MAX7219 Register Address
#define MAX7219_DECODE_MODE 0x09
#define MAX7219_INTENSITY 0x0a
#define MAX7219_SCAN_LIMIT 0x0b
#define MAX7219_SHUTDOWN 0x0C
#define MAX7219_DISPLAY_TEST 0x0f
void SPI_init(){
SSP1CON1 = 0b00100000; //SSP1EN=1:SSP1 Enable,CKP=0:Idle Low,Clock=FOSC/4
SSP1STAT = 0b01000000; //SMP=0:middle,CKE=1:Active to Idle
}
void maxTransfer(uint8_t address,uint8_t data){
CS = 0;
uint8_t dammy;
//send address
dammy = SSP1BUF;
SSP1BUF = address;
while(!SSP1STATbits.BF);
//send data
dammy = SSP1BUF;
SSP1BUF = data;
while(!SSP1STATbits.BF);
CS =1;
}
void MAX7219_init(){
maxTransfer(MAX7219_DECODE_MODE, 0xff);// Code B decode for digits 7-0
maxTransfer(MAX7219_INTENSITY, 0x03); // Intensity
maxTransfer(MAX7219_SCAN_LIMIT, 0x07);// Display digits 01234567
maxTransfer(MAX7219_SHUTDOWN, 0x01);// Normal Operation
maxTransfer(MAX7219_DISPLAY_TEST, 0x00);// Normal Operation
}
void Clear_Display(){
for(uint8_t i=1;i<=8;i++){
maxTransfer(i,0x0f);
}
}
void main(){
ANSELA = 0b00000000 ; // AN0-AN4は使用しない
ANSELB = 0b00000000 ; // AN5-AN11は使用しない
TRISA = 0b00000000 ; // PORTAは全て出力(RA5は入力)
TRISB = 0b00000000 ; // PORTBは全て出力
PORTA = 0b00000000 ; // PORTA初期化
PORTB = 0b00000000 ; // PORTB初期化
CS = 1; //CS初期値
SPI_init(); //SPI初期化
MAX7219_init(); //MAX7219初期化
Clear_Display(); //ディスプレイクリア
for(uint8_t i=1;i<=8;i++){
maxTransfer(i,i);
__delay_ms(1000);
}
while(1){
maxTransfer(MAX7219_DISPLAY_TEST, 0x01);// 全点灯
__delay_ms(500);
maxTransfer(MAX7219_DISPLAY_TEST, 0x00);// normal mode
__delay_ms(500);
}
}
--------------------------------------------------------------------
ディスプレイをクリアした後、Digit0からDigit7に1から8を表示し、その後、全点灯とノーマル表示を0.5秒ごとに表示します。
ノーマル表示の様子です。数10mA程度の電流が流れます。
全点灯の様子です。200mA程度電流が流れます。
※コメント投稿者のブログIDはブログ作成者のみに通知されます