
自分なりに考え全セグメントをダイナミック点灯出来ましたが、
下記のタイマー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();
}}}}
No.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を長押ししたらアジャストモード、みたいなのを作るのでしょうね。編集中の桁は点滅させたりとかして。ここでも複数回の割り込みをうまく検知して…といった処理を作ることになると思います。徐々に慣れていってわかってくると、だんだん楽しくなってくると思います。
ありがとうございます。
これで、7セグのほぼ表示は出来るようになりましたので、
完成したも同然です。(デバッグ実行中です。)
クロック入力は、現在はクリスタルですが、
現段階の状況は、24時間で8秒進む計算なので、
高精度クリスタルオシレーターそ付けます。
また一つ勉強になりました。
No.2
- 回答日時:
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);
No.1
- 回答日時:
そのデバイスやコンパイラを知らないので何とも言えませんが、構造体と配列を使うことができるのであれば、与えた数値をもとに各セグメントに代入するようにした方が考えやすいです。
// 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セグを書き換えることのコストが高いようであれば、各桁の前回の値を覚えておき、変化したらその桁だけ書き換える、という方法でもいいと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(データベース) 「1004:アプリケーション定義またはオブジェクト定義のエラー」への解消方法に関して 1 2023/07/09 11:47
- Excel(エクセル) マクロだと数式が表示される 2 2022/09/10 14:48
- 工学 制御工学の問題について 2 2022/10/30 20:20
- Visual Basic(VBA) VBAが止まります。 3 2022/08/31 14:09
- Excel(エクセル) Excelのセルのコピーについて 4 2022/12/26 15:01
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- 建設業・製造業 自分 大工してます。 木造造作 RC造作 鉄骨造作 リフォーム出来ます…が。 木造だけやる大工さん 1 2022/08/21 09:20
- ラジコン・ミニ四駆 蝶のようなRCはありますか。 アゲハチョウくらいの大きさ。 トンボのようなRCはありますか。 シオカ 2 2023/05/03 09:35
- Visual Basic(VBA) VBAでoutlook365が起動しません。 4 2022/08/25 13:31
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Arduinoを使ってMIDI機器のコン...
-
VC++でGetKeyboardStateがうま...
-
既定のコンストラクタがありま...
-
プログラミング教えてください
-
OpenSSLのSHA1関連の関数はどこ...
-
const_castのつかいどころを教...
-
(void)0 はどんな意味ですか
-
リージョンのフレームを描画す...
-
gcc: incompatible pointer type
-
見た目は同じソースなのにエラ...
-
カノニカルモードの設定について
-
静的でないメンバ関数の呼び出...
-
C言語 ① 5秒間 1秒間隔で点滅を...
-
ソケット通信時のWSACleanup処...
-
GDI+の使用方法について
-
C++でイベントドリブンなコード...
-
C/C++でのScene管理について
-
「Aに対するBの割合」と「Aに対...
-
fgetsなどのときのstdinのバッ...
-
信頼区間の1.96や1.65ってどこ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
静的でないメンバ関数の呼び出...
-
【gcc・cygwin】multiple defin...
-
戻り値を返す関数の前に(void)...
-
多重定義が起きている?--lnk20...
-
C++にてtemplateで受け取った任...
-
const_castのつかいどころを教...
-
既定のコンストラクタがありま...
-
C# Controls.Addで動的に配置し...
-
(void)0 はどんな意味ですか
-
C#でラジオボタンを設定に記録...
-
ウインドウの移動禁止
-
Notepad++の関数リスト表示の変...
-
Delphiの定数とローカル変数の...
-
typedef unsigned int UINT;が...
-
int main()、void main()、void...
-
C言語 extern について
-
void*型の配列について
-
VC++でGetKeyboardStateがうま...
-
_beginthreadにて発生するコン...
-
gcc: incompatible pointer type
おすすめ情報
大変恐縮でありますが、
>4桁の7セグに何を表示するかは適当に考えるとして、数字の2桁表示は、例えば次のような関数で10の位、1の位にバラせます。
のところですが、3桁目、4桁目の分解方法も教えて頂けますでしょうか。
趣味でプログラミングをしている者なので、優しくご教示お願いします。