dポイントプレゼントキャンペーン実施中!

自分なりに考え全セグメントをダイナミック点灯出来ましたが、
下記のタイマー4で1秒毎にカウントアップし9を超えたら次の桁にシフトして、
10~99まで表示し、3桁、4桁目も同様にしたいのですが、いくら考えてもやり方が思い浮かびません
お力をお貸しください。
コンパイラ XC8
PIC16F1933
最終的な目標は目覚まし時計兼タイマーです。
よろしくお願いします。
ソースここからーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
#include <xc.h>
#define _XTAL_FREQ 8000000
// CONFIG1
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config CLKOUTEN = OFF
#pragma config IESO = ON
#pragma config FCMEN = ON

// CONFIG2
#pragma config WRT = OFF
#pragma config VCAPEN = OFF
#pragma config PLLEN = OFF
#pragma config STVREN = ON
#pragma config BORV = HI
#pragma config LVP = ON
__EEPROM_DATA(0x09,0x1E,0xff,0xff,0xff,0xff,0xff,0xff);
unsigned int Count, Count4;
unsigned int flg = 0;
unsigned int second_flg = 0;
unsigned int second = 0;
unsigned int Minits = 0;
unsigned int Hours = 0;
void zero(void){
// 0 ABCDEF
RC0 = 1;
RC1 = 1;
RC2 = 1;
RC3 = 1;
RC4 = 1;
RC5 = 1;
}
void one(void){
// 1 BC
RC1 = 1;
RC2 = 1;
}
void two(void){
// 2 ABGDE
RC0 = 1;
RC1 = 1;
RC3 = 1;
RC4 = 1;
RC6 = 1;
}
void three(void){
// 3 ABCDG
RC0 = 1;
RC1 = 1;
RC2 = 1;
RC3 = 1;
RC6 = 1;
}
void four(void){
// 4 BCGF
RC1 = 1;
RC2 = 1;
RC5 = 1;
RC6 = 1;
}
void five(void){

// 5 ACDFG
RC0 = 1;
RC2 = 1;
RC3 = 1;
RC5 = 1;
RC6 = 1;
}
void six(void){
// 6 AFECDG
RC0 = 1;
RC2 = 1;
RC3 = 1;
RC4 = 1;
RC5 = 1;
RC6 = 1;
}
void seven(void){

// 7 ABCF
RC0 = 1;
RC1 = 1;
RC2 = 1;
RC5 = 1;
}
void eight(void){
// 8 ABCDEFG
RC0 = 1;
RC1 = 1;
RC2 = 1;
RC3 = 1;
RC4 = 1;
RC5 = 1;
RC6 = 1;
}
void nine(void){
// 9 ABCDFG
RC0 = 1;
RC1 = 1;
RC2 = 1;
RC3 = 1;
RC5 = 1;
RC6 = 1;
}
void Hour(void){
// Hour BCEFG
RC1 = 1;
RC2 = 1;
RC4 = 1;
RC5 = 1;
RC6 = 1;
}
void DP(void){
// DP
RC7 = 1;
}
void d(void){
// d BCDEG
RC1 = 1;
RC2 = 1;
RC3 = 1;
RC4 = 1;
RC6 = 1;
}
// タイマー割込みの処理
void interrupt InterTimer( void ){
if (TMR2IF == 1) { // タイマー2の割込み発生か?
TMR2IF = 0 ; // タイマー2割込フラグをリセット
flg++;
if(flg >= 5){
flg = 0;
}
}
if(TMR4IF == 1){
TMR4IF = 0;
Count4++;
if(Count4 >= 125){ // 1秒
Count4 = 0;
Minits++;
if(Minits >= 61){ // 1分
Minits = 0;
Hours++;
if(Hours >= 360){ // 360時間
Hours = 0;
}}
if(second_flg == 0){
second_flg = 1;
}else{
second_flg = 0;
}}}}
void port_clear(void){
PORTA = 0b00000000;
PORTB = 0b00000000;
PORTC = 0b00000000;
}
void main(){
OSCCON = 0b00000000 ; // 外部クロックは8MHzとする
ANSELA = 0b00000000 ; // AN0-AN4は使用しない全てデジタルI/Oとする
ANSELB = 0b00000000 ; // AN8-AN13は使用しない全てデジタルI/Oとする
TRISA = 0b00000000 ; // ピン(RA)は全て出力に割当てる(0:出力 1:入力)
TRISB = 0b00000000 ; // ピン(RB)は全て出力に割当てる
TRISC = 0b00000000 ; // ピン(RC)は全て出力に割当てる
PORTA = 0b00000000 ; // RA出力ピンの初期化(全てLOWにする)
PORTB = 0b00000000 ; // RB出力ピンの初期化(全てLOWにする)
PORTC = 0b00000000 ; // RC出力ピンの初期化(全てLOWにする)

T2CON = 0b00000111;
PR2 = 100;
TMR2 = 0;
Count = 0;
TMR2IF = 0;
TMR2IE = 1;
T4CON = 0b00000111;
PR4 = 249;
TMR4 = 0;
Count4 = 0;
TMR4IF = 0;
TMR4IE = 1;
PEIE = 1;
GIE = 1;
while(1) {
if(flg == 1){ // 4桁目
RB0 = 1;
RB1 = 0;
RB2 = 0;
RB3 = 0;
one();
port_clear();
}else if(flg == 2){ // 3桁目
RB0 = 0;
RB1 = 1;
RB2 = 0;
RB3 = 0;
two();
port_clear();
}else if(flg == 3){ // 2桁目
RB0 = 0;
RB1 = 0;
RB2 = 1;
RB3 = 0;
zero();
port_clear();
}else if(flg == 4){ // 1桁目
RB0 = 0;
RB1 = 0;
RB2 = 0;
RB3 = 1;
Hour();
if(second_flg == 1){
RB0 = 0;
RB1 = 0;
RB2 = 0;
RB3 = 1;
Hour();
DP();
port_clear();
}else{
RB0 = 0;
RB1 = 0;
RB2 = 0;
RB3 = 1;
Hour();
port_clear();
}}}}

質問者からの補足コメント

  • 大変恐縮でありますが、
    >4桁の7セグに何を表示するかは適当に考えるとして、数字の2桁表示は、例えば次のような関数で10の位、1の位にバラせます。
    のところですが、3桁目、4桁目の分解方法も教えて頂けますでしょうか。
    趣味でプログラミングをしている者なので、優しくご教示お願いします。

    No.2の回答に寄せられた補足コメントです。 補足日時:2017/11/09 19:17

A 回答 (3件)

No.2です。

補足を読みました。

>趣味でプログラミングをしている者なので、優しくご教示お願いします。

私も趣味の範疇で回答しています。
No.1の冒頭で言っているように、私はその実機のこともコンパイラのこともわかりませんので、具体的な表示手続きや割り込みの発生タイミングなどについて正しく回答することができません。なので、たとえばset_seg7()関数の中身は間違っているかもしれません(barasu()はデバイスに依存しないので自信がありますけど)。もっと身も蓋もないことを言ってしまえば、こういったマイコン制御をCで書いたこともありません(機械語で書いたことはありますけど)ので、特にデバイス制御系の処理の部分はあまり鵜呑みにしないでください。

まずディスプレイに何を表示するかですが、7セグが
D4 D3 D2 D1
と並んでいるとして、D4とD3に「時」を、D2とD1に「分」を表示する時計にする場合には、

No.1, No.2の回答に書いた記号に倣えば

int sec, sec10, sec1;
int min, min10, min1;
int hour, hour10, hour10;

と宣言したとして(secは秒数、minは分数、hourは時間数)、
分は
barasu(min, &min10, &min1); //「分」の数字の10の位と1の位を求める
として、D1、D2それぞれについて

// 1の位を表示
D1を操作するセッティング();
set_seg7(min1);
7セグ書き換え();

// 10の位を表示
D2を操作するセッティング();
set_seg7(min10);
7セグ書き換え();

時も同様に、
barasu(hour, &hour10, &hour1);
として、D3、D4それぞれについて
D3を操作するセッティング();
set_seg7(hour1);
7セグ書き換え();
D4を操作するセッティング();
set_seg7(hour10);
7セグ書き換え();

という感じになると思います。
また、ストップウォッチのようにD4とD3に「分」を、D2とD1に「秒」を表示するならば、
それぞれ上記の例をhour→min、min→secと読み替えればいいと思います。

将来的には、入力デバイスにボタンがあるならば、例えばボタン2を長押ししたらアジャストモード、みたいなのを作るのでしょうね。編集中の桁は点滅させたりとかして。ここでも複数回の割り込みをうまく検知して…といった処理を作ることになると思います。徐々に慣れていってわかってくると、だんだん楽しくなってくると思います。
    • good
    • 0
この回答へのお礼

ありがとうございます。
これで、7セグのほぼ表示は出来るようになりましたので、
完成したも同然です。(デバッグ実行中です。)
クロック入力は、現在はクリスタルですが、
現段階の状況は、24時間で8秒進む計算なので、
高精度クリスタルオシレーターそ付けます。
また一つ勉強になりました。

お礼日時:2017/11/10 23:11

No.1です。



すみません、よくよく読んでみると、7セグは4個なのですね。
また、クロック周波数8MHzというところから、
・演算はALUが搭載されているが乗算・除算器はない?
・1クロックで演算完了するのでパイプライン化されておらず条件分岐のコストはそれほど高くない?
という特性の演算ユニットなのかなと想像します。

としますと、時間のカウントは桁ごとに繰り上がりする方が現実的ですね。
int sec, min, hour;

if (1秒経過) {
sec ++;
} else {
return;
}

if (sec >= 60) {
min ++;
sec = 0;
}

if (min >= 60) {
hour ++;
min = 0;
}

if (hour >= 24) {
hour = 0;
}

4桁の7セグに何を表示するかは適当に考えるとして、数字の2桁表示は、例えば次のような関数で10の位、1の位にバラせます。

void
barasu(int n, int *n10, int *n1)
{
int c = 0;
while (n >= 10) {
n -= 10;
c ++;
}
*n1 = n;
*n10 = c;
return;
}

int sec, sec10, sec1;
sec = 数字;

barasu(sec, &sec10, &sec1);
この回答への補足あり
    • good
    • 0
この回答へのお礼

ありがとうございます。
補足もしますので回答お願いします。

お礼日時:2017/11/09 19:13

そのデバイスやコンパイラを知らないので何とも言えませんが、構造体と配列を使うことができるのであれば、与えた数値をもとに各セグメントに代入するようにした方が考えやすいです。



// RB0などの型に合わせてメンバの型は読み替えてください
struct seg7 {
int rb0;
int rb1;
int rb2;
int rb3;
int rb4;
int rb5;
int rb6;
}

// 7segのパターンを作る
struct seg7 number[10] = {
{1, 1, 1, 1, 1, 1, 0}, // 0:ABCDEFg
{0, 1, 1, 0, 0, 0, 0}, // 1:aBCdefg
....
{1, 1, 1, 1, 0, 1, 1} // 9:ABCDeFG
};

void
set_seg7(int x)
{
RB0 = number[x].rb0;
RB1 = number[x].rb1;
...
RB6 = number[x].rb6;
}

こうすれば、例えば0という数値の7セグのパターンは、
set_seg7(0);
とする(引数に数値を与える)と、RB0~RB6にそれぞれ0か1を代入できます。

割り込みのタイミングやカウントの仕方はよくわからないので模式的に書きますが、例えば00:00:00を0、23:59:59を86399とするならば、
int count = 現在時刻とか;

void
interrupt()
{
if (1秒経過していたら) {
count ++;
count = count % 86400; // 24:00:00になったら00:00:00にする
// 時の2桁目
時の2桁目を操作するセッティング();
set_seg7(count / 36000);
7セグ書き換え();
// 時の1桁目
時の1桁目を操作するセッティング();
set_seg7((count / 3600) % 10);
7セグ書き換え();
// 分の2桁目
分の2桁目を操作するセッティング();
set_seg7((count % 3600) / 600);
7セグ書き換え();
// 分の1桁目
分の1桁目を操作するセッティング();
set_seg7(((count % 3600) / 60) % 10);
7セグ書き換え();
// 秒の2桁目
秒の2桁目を操作するセッティング();
set_seg7((count % 60) / 10);
7セグ書き換え();
// 秒の1桁目
秒の1桁目を操作するセッティング();
set_seg7((count % 60) % 10);
7セグ書き換え();
}
...
}

みたいな感じにすればいいんじゃないかと思います。
set_seg7()の引数は、あっているかどうかわかりません(すみません、無責任で)。
要するに、数値と7セグパターンを結びつけることと、すべての7セグを書き換えることがポイントです。
すべての7セグを書き換えることのコストが高いようであれば、各桁の前回の値を覚えておき、変化したらその桁だけ書き換える、という方法でもいいと思います。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


このQ&Aを見た人がよく見るQ&A