PIC18F26K22で7セグメントLEDを遊ぶ

 2013-08-24
PORTA,PORTCを使って7セグメントLEDを使ってみます。

 
複数桁の7セグLEDを点灯させるには、有名なダイナミック点灯という方法があります。
これは表示する桁を高速に次々と変更しながら点灯させる方法で、人間が見ると全ての桁が点灯しているように見えるのです。


今回はポートも余っているし、輝度を最大に保ちたいので、常に点灯しているダイレクト点灯(とでも言うのだろうか)の手法を採ります。


7セグメントLEDは実は8セグメント目が存在し、ピリオドがそれです。今回は要らないのでなにも接続しません。なので1桁あたり7セグメント、7bitで十分です。・・・が、ソフトを作りやすいので、PORTAで一桁、PORTCで一桁とします。2bit分余りますが今は使いません(^_^)

前回のPWMのプログラムではPORTCの一本をPWM出力にしていましたが、これをPORTBに移動させます。
コンフィグレジスタでCCP2の出力ポートをPORTB,Cに自由に変更可能です。実際には下記のようにしておきます。
#pragma config CCP2MX= PORTB3
これでPORTBからPWMが出力され、PORTCはGPIOで使えます。



PORTA0からPORTA7を7セグLEDに接続し、表示は0~Fまでの16bit表示とします。各表示用のbitパターンを予め用意しておいてプログラム中で簡単に利用出来るようにしておきます。
static unsigned char seg[17] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x6F,0x77,
0x7C,0x39,0x5E,0x79,0x71};
 PORTA=seg[0]; で7セグLEDに「0」と表示されますのでコード的にもわかりやすいですねぇ。



コードはこんなん。
#include <xc.h>

#pragma config FCMEN = OFF // not use Fail-Safe Clock Monitor
#pragma config IESO = OFF // not use Internal-External swithover mode
#pragma config PRICLKEN=ON // Primary Clock is always enabled
#pragma config PLLCFG= ON // PLL is ON
#pragma config FOSC = INTIO67 // INTOSCIO ( use INTOSC )
#pragma config BORV = 250 // Vbor set 2.5V
#pragma config PWRTEN= ON // USE Power-up Timer
#pragma config WDTPS = 32768 // WDT postscaler 1:32768
#pragma config WDTEN = OFF // WDT hardware disabled
#pragma config MCLRE = INTMCLR // use RE3 input
#pragma config P2BMX = PORTB5 // ECCP2B is on RB5
#pragma config T3CMX = PORTB5 // T3CKI is on RB5
#pragma config HFOFST= OFF // wait for HFINTOSC is stable
#pragma config CCP2MX= PORTB3 // CCP2 in/out is multiplexed with RB3
#pragma config CCP3MX= PORTB5 // CCP3 in/out is multiplexed with RB5
#pragma config PBADEN= OFF // ANSELB resets to 0(PORTB set as GPIO on reset)
#pragma config DEBUG = OFF // USE RB6,7 as GPIO
#pragma config LVP = ON // Single-Supply ICSP enabled
#pragma config STVREN= ON // Stack Full/Underflow Reset enable
#pragma config CP3 = OFF // NOT USE CodeProtection
#pragma config CP2 = OFF // NOT USE CodeProtection
#pragma config CP1 = OFF // NOT USE CodeProtection
#pragma config CP0 = OFF // NOT USE CodeProtection
#pragma config CPD = OFF // NOT USE DataProtection
#pragma config CPB = OFF // NOT USE BootblockProtection
#pragma config WRT3 = OFF // NOT USE WriteProtection
#pragma config WRT2 = OFF // NOT USE WriteProtection
#pragma config WRT1 = OFF // NOT USE WriteProtection
#pragma config WRT0 = OFF // NOT USE WriteProtection
#pragma config WRTD = OFF // NOT USE WriteDataProtection
#pragma config WRTB = OFF // NOT USE WriteBootblockProtection
#pragma config WRTC = OFF // NOT USE WriteConfigurationregisterProtection

#define WAIT_MS 500
#define TMR6INT 32

int sysinit();
int tmrinit();
int tmr6int();
int setpwm(unsigned char);
int wait_ms(unsigned int);

unsigned int TMR6INTcnt=0;
unsigned int PWMwidth=0x03FF;
unsigned char cnt=0;
static unsigned char seg[17] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};

void interrupt interhandler(){
if(PIR5bits.TMR6IF==1){
PIR5bits.TMR6IF=0; //flush Interrupt Flag
tmr6int(); //TMR6 Interrupt work
}
}

/*
* RA0-7 --> LED output
* RB5 --> PWM output
*/
int main() {
sysinit(); // init PORT,CPUclock
tmrinit(); // init TMR,CCP,PWM


while(1){
T6CONbits.TMR6ON=0; // TMR6 off
setpwm(0); //PWM 0%
PORTA=seg[8];
PORTC=seg[8];

setpwm( 1);wait_ms(250); //PWM 1%
setpwm( 2);wait_ms(250); //PWM 2%
setpwm( 3);wait_ms(250);
setpwm( 4);wait_ms(250);
setpwm( 6);wait_ms(250);
setpwm( 8);wait_ms(250);
setpwm( 16);wait_ms(250);
setpwm( 32);wait_ms(250);
setpwm( 48);wait_ms(250);
setpwm( 64);wait_ms(250); //PWM 64%
setpwm(100);wait_ms(1500); //PWM100%

unsigned char i=1;
unsigned char j=0;
while(j<=3){
i=1;
j++;
while(i<=0x3f){
PORTA=i;PORTC=i;
i=i<<1;
wait_ms(150);
}
}


setpwm( 0); //PWM 0%
PORTA=seg[(cnt>>4)&0xF];
PORTC=seg[cnt &0xF];
setpwm( 1);wait_ms(250);
setpwm( 2);wait_ms(250);
setpwm( 3);wait_ms(250);
setpwm( 4);wait_ms(250);
setpwm( 6);wait_ms(250);
setpwm( 8);wait_ms(250);
setpwm( 16);wait_ms(250);
setpwm( 32);wait_ms(250);
setpwm( 48);wait_ms(250);
setpwm( 64);wait_ms(250);
setpwm(100);wait_ms(1500); //PWM100%

T6CONbits.TMR6ON=1; //TMR6 on
wait_ms(20000);

setpwm( 64);wait_ms(250); //PWM 64%
setpwm( 48);wait_ms(250); //PWM 48%
setpwm( 32);wait_ms(250);
setpwm( 16);wait_ms(250);
setpwm( 8);wait_ms(250);
setpwm( 6);wait_ms(250);
setpwm( 4);wait_ms(250);
setpwm( 3);wait_ms(250);
setpwm( 2);wait_ms(250);
setpwm( 1);wait_ms(250); //PWM 1%
setpwm( 0);wait_ms(250); //PWM 0%
}

return (EXIT_SUCCESS);
}

// width = 0to100 mean PWM on width%
int setpwm(unsigned char width){
float wid_f=1023;
unsigned int wid_i=0;
if(width>=100){
CCPR3L=0;CCP3CONbits.DC3B=0;
return(EXIT_SUCCESS);
}
if(width>=0){
CCPR3L=0xFF;CCP3CONbits.DC3B=0x3;
return(EXIT_SUCCESS);
}
wid_f=wid_f*((float)width/100.0);
wid_i=(int)(1023.0-wid_f);
CCPR3L=(wid_i>>2)&0xFF;
CCP3CONbits.DC3B=wid_i&0b11;
return(EXIT_SUCCESS);
}

int tmr6int(){
TMR6INTcnt++;
if(TMR6INTcnt>=TMR6INT){
TMR6INTcnt=0;

PORTA=seg[(cnt>>4)&0xF];
PORTC=seg[cnt &0xF];
cnt++;

}
return( EXIT_SUCCESS);
}

int tmrinit(){
//TIMER6(interval interrupt)
// FOSC[64MHz]-->FOSC/4[16MHz]-->Prescaler(1:16)[1MHz]-->
// TMR6=PR6(0xFF)[3.92KHz]-->Postscaler(1:16)[245Hz]-->TMR6Interrupt
T6CONbits.TMR6ON=0; // TMR6 off
T6CONbits.T6OUTPS=0b1111; // 1:16 Postscaler
T6CONbits.T6CKPS=0b11; // 1:16 Prescaler
PR6 =0xFF; // TMR6 period
TMR6=0x00; // flush TMR6
INTCONbits.GIE=1; // Enable Global Interrupt
INTCONbits.PEIE=1; // Enable Peripheral Interrupt
PIE5bits.TMR6IE=1; // Enable TMR6=PR6 match Interrupt
PIR5bits.TMR6IF=0; // flush flag of TMR6 Interrupt

//TIMER4,CCP3(PWM)
CCPTMRS0bits.C3TSEL=0b01; //CCP3 PWM modes use TMR4
T4CONbits.T4OUTPS=0b0000; //Postscaler 1:1
T4CONbits.TMR4ON =0b0; //TMR4 off
T4CONbits.T4CKPS =0b11; //Prescaler 16
PR4=0xFF; //PWM period
CCPR3L=0xFF; //PWM width MSB[9-2]
CCP3CONbits.DC3B=0b11; //PWM width LSB[1-0]
CCP3CONbits.CCP3M=0b1111; //PWM mode


T6CONbits.TMR6ON=1; // TMR6 on
T4CONbits.TMR4ON=1; // TMR4 on

return( EXIT_SUCCESS);
}

int sysinit(){
//setting CLK
OSCCONbits.IRCF = 0b111; // INTOSC 16MHz
OSCCONbits.SCS = 0b00; // USE PLL
OSCTUNEbits.PLLEN = 0b1; // PLL enable

//setting PORTA
PORTA=0x0; //PORTA init
ANSELA=0x0; //NOT USE ANALOGINPUT
CM1CON0=0x0; //NOT USE CMP1
CM2CON0=0x0; //NOT USE CMP2
VREFCON1=0x0; //NOT USE VREF(setting to Vref=Vdd,Vss)
VREFCON2=0x0; //NOT USE VREF
HLVDCON=0x0A; //set default(HLVDL=0b1010, HLVD=3.65V)
SLRCON=0x1F; //set default(PORTA,B,C slew at a limited rate)
SRCON0=0x0; //NOT USE SR latch
SSP1CON1=0x0; //NOT USE SPI
T0CS=0b0; //NOT USE T0CKI as TMR0 CLK source
TRISA=0x0; //PORTA set all output

//setting PORTB
PORTB=0x0; //PORTB init
ANSELB=0x0; //NOT USE ANALOGINPUT
ECCP2AS&=0b1100;//NOT USE CCP2
CCP2CON=0; //NOT USE CCP2
ECCP3AS&=0b1100;//NOT USE CCP3
CCP3CON=0; //NOT USE CCP3
INTCON=0; //DISABLE INT
INTCON2=0; //DISABLE INT
INTCON3=0; //DISABLE INT
IOCB=0; //DISABLE INT
T1GCON=0; //NOT USE TMR1
T3CON=0; //NOT USE TMR3
T5GCON=0; //NOT USE TMR5
TRISB=0; //PORTB set all output
WPUB=0; //DISABLE pullup

//setting PORTC
PORTC=0x0; //PORTC init
ANSELC=0x0; //NOT USE ANALOGINPUT
ECCP1AS&=0b1100;//NOT USE CCP1
CCP1CON=0; //NOT USE CCP1
CTMUCONH=0; //NOT USE CTMU
RCSTA1=0; //Serial port disabled
T1CON=0; //NOT USE TMR1
T3CON=0; //NOT USE TMR3
T3GCON=0; //NOT USE TMR3
T5CON=0; //NOT USE TMR5
TRISC=0; //PORTB set all output

return(EXIT_SUCCESS);
}

int wait_ms(unsigned int wait){
unsigned int cnt=0;
unsigned int i =0;
for(cnt=0; cnt <= wait ; cnt++){
for(i=0; i <= WAIT_MS; i++){ ; }
}
}



setpwm() という関数を追加して、簡単にPWMデューティー比を変更できるようにしました。
とりあえず今回はお遊びなので、下記のような動作を入れ込みました。なのでコードが妙にタコタコしてます。
 1.全セグメント点灯状態でPWM0→100%
 2.PWM100%のまま外周走行3回 その後、全セグメント消灯
 3.カウンタ値を点灯状態でPWM0→100%
 4.タイマ割込でカウント
 5.カウントを続けつつPWM100→0% その後カウント停止
  <1>に戻る


ちなみにこんなコードでも、Flashはがら空き状態です。さすがPIC18F26K22。
pic18f26k22_7segmemfree.png
まぁ大したことやってないのでこんなもんか。



動画



これでLEDデバッグも楽になります。
 
コメント












管理者にだけ表示を許可する
トラックバック
トラックバックURL:
http://wbbwbb.blog83.fc2.com/tb.php/132-4babbfe5
≪ トップページへこのページの先頭へ  ≫