質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

セグメント

セグメントは、複数の連続するIPアドレスをまとめて ひとつのネットワークとして一度にアクセスできる領域のことです。

mbed

mbed(エンベッド)は、Webサイト上でC++を使って開発を行う、ワンボードマイコンのプロトタイピングツールです。PCに開発環境をインストールする必要がなく、Webにアクセスできればどこにいても開発を行うことができます。

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

Q&A

3回答

2339閲覧

時間計測過程を7セグメントLEDに出力したい

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

セグメント

セグメントは、複数の連続するIPアドレスをまとめて ひとつのネットワークとして一度にアクセスできる領域のことです。

mbed

mbed(エンベッド)は、Webサイト上でC++を使って開発を行う、ワンボードマイコンのプロトタイピングツールです。PCに開発環境をインストールする必要がなく、Webにアクセスできればどこにいても開発を行うことができます。

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

0グッド

0クリップ

投稿2020/01/03 08:55

7セグメントLEDを用いたストップウォッチ

はじめまして。
C言語は初心者ですが質問です。
ただいまmbedマイコンと7セグメントLEDを用いたストップウォッチを作成しようと考えているのですが、このプログラムはtime.hをインクルードして使うclock関数を用いてそれを7セグに出力する、という形になるのでしょうか?そうなるとどのようにして時間計測?をしている過程を7セグに出力するのかがわかりません、、。
また、0.001秒ごとに1ずつ値を増やしていって10や60といった決まった値になったら繰り上げる、、、というのを繰り返したらいい感じのができそうだと感じましたが、そうなったら止め方がわからなくなったり、コードにエラー(下記参照)が発生して更にわからなくなってしまいました。周りの友人に聞いてもプログラミングに詳しい人がいない為情報を得ることができず、またネットで調べても十分な情報が得られなかったので、どなたかヒントを教えていただけると嬉しいです。

試したこと

・time.hをインクルードしてclock関数を使うのかなと思ったもののそれをどのようにしたら時間計測の過程も出力できるのかがわからなくなった。

・だったら0.001秒ごとに1ずつ値を増やしていって10や60といった決まった値になったら繰り上げる、、、というのを繰り返したらいい感じのができそうだと感じたけどそうなったら止め方がわからなくなった。プログラムはこんな感じです↓

C++

1#include "mbed.h" 2 3DigitalOut a(p10); 4DigitalOut b(p11); 5DigitalOut c(p12); 6DigitalOut d(p13); 7DigitalOut e(p14); 8DigitalOut f(p15); 9DigitalOut g(p16); 10DigitalOut dp(p17); 11 12DigitalOut dig1(p21); 13DigitalOut dig2(p22); 14DigitalOut dig3(p23); 15DigitalOut dig4(p24); 16 17DigitalIn mysw(p9); 18 19int main() { 20 21 int num; 22 int i = 1; 23 int cs = dig4; 24 int ds = dig3; 25 int s = dig2; 26 int m = dig1; 27 28 if (num == 0) { a=1; b=1; c=1; d=1; e=1; f=1; g=0; } 29 else if (num == 1) { a=0; b=1; c=1; d=0; e=0; f=0; g=0; } 30 else if (num == 2) { a=1; b=1; c=0; d=1; e=1; f=0; g=1; } 31 else if (num == 3) { a=1; b=1; c=1; d=1; e=0; f=0; g=1; } 32 else if (num == 4) { a=0; b=1; c=1; d=0; e=0; f=1; g=1; } 33 else if (num == 5) { a=1; b=0; c=1; d=1; e=0; f=1; g=1; } 34 else if (num == 6) { a=1; b=0; c=1; d=1; e=1; f=1; g=1; } 35 else if (num == 7) { a=1; b=1; c=1; d=0; e=0; f=1; g=0; } 36 else if (num == 8) { a=1; b=1; c=1; d=1; e=1; f=1; g=1; } 37 else if (num == 9) { a=1; b=1; c=1; d=1; e=0; f=1; g=1; } 38 39 while (1) { 40 if (mysw==1) { 41 wait (0.001); 42 cs ++; 43 } 44 45 if (cs == 10) { 46 ds ++; 47 } 48 49 if (ds == 10) { 50 s ++; 51 } 52 53 if (s == 10) { 54 m ++; 55 } 56 } else if (mysw==0) { 57 cs = 0; 58 ds = 0; 59 s = 0; 60 m = 0; 61 } 62 63}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

mbedと言ってもいろいろありますけれど。お使いのはLPC1768とかですか?

ストップウオッチなら、mbed::Timerクラスを使うのが楽そうに思います。

ネットで調べても十分な情報が得られなかったので

質問を読む限り、C/C++の知識が決定的に足りない状況に思えます。
他人のプログラムをコピーしてちょっと改造するくらいならともかく、自分でなにか作ろう、というのならやはりC/C++の入門書くらいは一通り目を通さないとさすがに歯が立たないのではないでしょうか。
まぁ、ネット上でも入門向けの記事とかはあるのでそれを読み通す、というならそれでもいいですけれど。(でも私はC++で入門から、という記事を知らない)

投稿2020/01/03 13:48

thkana

総合スコア7629

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/01/14 08:29

ありがとうございます。Timerクラスに関して調べてみましたが確かに楽そうですね。LPC1768を使っています。ですがあまりよくわからなくて、、。
guest

0

そもそもターゲットマイコンが何であるか、開発環境がどんなものか、わからないのですが、それを示されても私が調べられるとは限りません(苦笑)。いろいろ推測を交えて書きます。

time.hをインクルードして使うclock関数を用いて
それを7セグに出力する、という形になるのでしょうか?

Linuxが動作するようなマイコンなら当然 clock() も使えるでしょう。
しかし、開発環境に依存することですが、7セグLEDが付くマイコンは小規模なことが多く、OSどころかそのような関数群は用意されていないことが多いです。私が経験したマイコンのC開発環境は、デフォルトでは printf() も使えませんでした。そのマイコンにとってどこが標準出力なのか、ということから考えなきゃいけない。
パソコンの開発環境とは違いますので、clock() 関数が用意されていない可能性は高いと思います。

ではどうするか。マイコンには様々な周辺機能が内蔵されていて、タイマ回路もそのひとつです。そのタイマを使って時間を計測するのがマイコンではスタンダードです。

どんな計算機にも一定の周波数のクロック信号がありますね。タイマの基本動作はクロックの波の数を数えることです。タイマに設定した数だけ波を数えたら目的の時間が経過した、ということですから、その時点でフラグが立ったりCPUに割込みをかけたりします。
因みに、この「フラグ」とは、プログラムの中に設けるフラグ変数ではなく、内蔵タイマが持っているレジスタの中の、ある1ビットのことです。最初から存在しています。ハードウェアマニュアルに説明があります。

C言語は初心者ですが
mbedマイコンと7セグメントLEDを用いたストップウォッチを作成しよう

7セグLEDとスイッチがあるなら、作るものはプログラムだけですが、C言語を理解するだけで作れると思ったら大間違い。ハードウェアを理解することが必須です。

ターゲットのハードウェアを理解せずに、目的の動作をするようなプログラムを書くことはできません。内蔵タイマなら、どう使えば目的の時間を測れるか、どんな値を設定すればよいか、タイマのハードウェア的な動作が見えてこないと考えようがありません。7セグLEDもスイッチも然り。

マイコンボードのハードウェアについて調べるべき基本的な資料が2種類あります。

  • マイコン内部(CPU、クロック、タイマ等内蔵周辺機能)はハードウェアマニュアル
  • マイコン外部(7セグLED、スイッチ、水晶発振子等)はターゲットボードの回路図

内蔵タイマを適切に初期化して、5msec. という時間を測れることがストップウォッチ実現の重要な構成要素になりそうです。そのために次の2点を明確にすることが大事です。

  • タイマをどう初期化するか、各種設定値はいくつか
  • 時間経過をフラグで監視するのか割込みを使うのか、おおまかに決める

で、今頃になって回答しようと思ったのは質問者が提示したコードを見て気づいたことがあるからです。
7セグLEDは4桁あるのではありませんか。推測にすぎないと言われればそれまでですが。

  • a(p10)〜dp(p17) は、4桁ある7セグメントLEDにつながるポート

これは質問者が理解した通り、表示する字形を指定するものです。この8本の信号は4桁ある7セグLEDを並列につないで、全く同じ信号を伝えます。それだと、4桁とも同じ数字しか表示できないのでは、という疑問に思うでしょう。ところが

  • dig1(p21)〜dig4(p24)は、4桁ある7セグメントLEDの、どの桁(digit)を光らせるかを指定するポート

であろう、これを用いて4桁それぞれ異なる数字を表示することができます。ダイナミック点灯と呼ぶ、これもスタンダードな方法です。ダイナミック点灯は

  1. dig1〜dig4 を全てオフにし、一旦全桁の表示を消す
  2. ある桁に表示する数字パターンをa(p10)〜dp(p17) にセットする
  3. その時点で表示する桁(dig?)だけをオンにし、その桁だけ数字を表示する
  4. 一定時間(この場合は5msec.以内)が経過するまで、そのまま放置
  5. 次の桁を表示するため 1.に戻る

という繰り返しです。一瞬だけなら一桁しか点灯していませんが、これを 20msec. 以下の周期で繰り返すと人間の目には残像として4桁の異なる数字が見えます。4桁なので5msec.毎に切り替えます。

質問者のコードは

C

1 int cs = dig4; // 0.01秒の桁?読み出し centi-second 2 int ds = dig3; // 0.1秒の桁?、読み出し deci-second 3 int s = dig2; // 秒の桁?、読み出し 4 int m = dig1; // 分の桁?、読み出し

と、全て読み出していますが、dig1〜dig4には出力しなければなりませんから、誤りだと思います。

ただし、いきなり4桁のダイナミック点灯を動かそうとするのは無謀です。ひと桁だけ表示する、全桁同じ数字を表示する、など比較的簡単な動作確認を済ませて、
タイマで5msec.を計測できることも確認したうえで、ようやくダイナミック点灯に挑戦できます。

もしかすると、開発環境にダイナミック点灯を実現しやすくするライブラリ関数が用意されているかもしれません。これも調べてみたら良いと思います。

0.001秒ごとに1ずつ値を増やしていって10や60といった決まった値になったら繰り上げる、
というのを繰り返したらいい感じのができそうだ

基本的な考え方はその通りです。ただし 0.001 秒は細かすぎます。1msec.毎に数字が変化しても人間の目では読み取れませんし4桁の7セグLEDに 0.01秒=10msec.単位で表示するのではありませんか。

なお、ある状態を一定時間保持する・一定時間毎に変化する・繰り返す、というようなプログラミングが初心者は苦手なものです。C言語の練習を兼ねて、パソコン上で clock(), sleep() 等を使って、表示が変わるような簡単なプログラムを、1秒単位のゆっくりした動作で構わないので、経験しておくと役に立ちます。

止め方がわからなくなったり

mysw(p9) につながったスイッチを読みだして、

  • スイッチが押されたらカウントを開始する
  • その後、スイッチが押されたらカウントアップを止める

ようにプログラムすれば良いだけだと思いますが。

スイッチの場合、チャタリング除去が必要であることを知っておきましょう。ハードウェア(スイッチ回路)がチャタリングを除去してくれる場合もありますし(その場合は読みだすだけで良いので簡単)、ソフトウェアで除去しなければならない場合もあります(やや面倒)。回路図を読めば見当がつくかもしれません。

もうひとつ、正論理・負論理について注意を。

  • 「オンが1、オフが0」となるポートを正論理(のポート)
  • 「オンが0、オフが1」となるポートを負論理(のポート)

と呼びます。たとえば

  • スイッチを押した時、そのポートを読んだ値は0か1か
  • LEDが点灯するのは0を出力したときか1を出力したときか

どちらであるかはマイコンボードの回路図があればわかります。これもハードウェアを理解できるかどうか、です。わからなければプログラムを作って確かめるという手もありますが。

ストップウォッチはマイコンで作る比較的簡単なアプリケーションですが、それでも

  • いくつかの構成要素に分解し
  • それぞれの動作確認を、段階を経ながら進めていき
  • 最後にストップウォッチ全体として完成させる

ことになります。何かすると一発でストップウォッチが動く、なんてことはありませんから。
Enjoy!


長々書いたけど、マイコンの一般論ということで orz
罪滅ぼしに、次のような前提で、即席のストップウォッチを書いてみました。何の検証もしていませんが、ご参考まで。

  • wait(0.005); で 5msec.時間待ちする
  • dig1 = 1; のように、表示桁を指定できる
  • if (mysw == 1) でスイッチが押されたか判定できる
  • スイッチは1個、押すたび カウントアップ→停止(表示)→リセット・・・状態を繰り返す
  • スイッチのチャタリング対策、というか、押しっぱなしに見えないように、delayカウンタ値が少ない期間はスイッチを見ないようにする(要調整)
  • --各ポートは正論理なのだろう~~dig1〜dig4は負論理だった!

C

1// ダイナミック点灯。ひと桁表示を更新 2void out7segled(int num, int digit) 3{ 4 dig1 = dig2 = dig3 = dig4 = 1; // いったん全桁消灯(負論理) 5 6 switch (num) { // 数字パターンを出力 7 case 0: a=1; b=1; c=1; d=1; e=1; f=1; g=0; break; 8 case 1: a=0; b=1; c=1; d=0; e=0; f=0; g=0; break; 9 case 2: a=1; b=1; c=0; d=1; e=1; f=0; g=1; break; 10 // (途中省略) 11 } 12 13 switch (digit) { // どの桁を点灯するか(負論理) 14 case 0: dig1 = 0; break; 15 case 1: dig2 = 0; break; 16 case 2: dig3 = 0; break; 17 case 3: dig4 = 0; break; 18 } 19} 20 21// 10msec毎に呼ばれ、タイマを10msec加算、 22void countup(int time[]) 23{ 24 if (++time[3] < 10) // ++cs, means "plus 10msec." 25 return; 26 time[3] = 0; // cs = 0(桁上がり) 27 if (++time[2] < 10) // ++ds, means "plus 100msec." 28 // (以下省略) 29} 30 31int main() 32{ 33 int time[4]; // = { m, s, ds, cs } 34 int status = 0; // 0: reset, 1: count up, 2: stop 35 int digit = 0; // time[] の添字 36 int toggle = 0; // 2回に一回 時計を 10msec.進める 37 int delay = 0; // 遅延カウンタ、スイッチを押した直後はスイッチを見ない 38#define NDELAY 10 // スイッチを見ない期間(チャタリング対策みたいな)要調整 39 while (1) { 40 wait (0.005); // 5msec.周期で繰り返す 41 42 // 今は reset, count up, stop の、どの状態? 43 switch (status) { 44 case 0: // リセット状態 45 time[0] = time[1] = time[2] = time[3] = 0; 46 if (++delay > NDELAY && mysw == 1) { 47 toggle = 0; // 5msecカウンタをクリアして 48 status = 1; // カウントアップ動作へ 49 delay = 0; // スイッチ見ない期間開始 50 } 51 break; 52 53 case 1: // カウントアップ状態 54 if (toggle == 1) 55 countup(time); // time += 10msec. (2回に1回) 56 toggle ^= 1; // 0, 1, 0, 1, 0 ... 57 58 if (++delay > NDELAY && mysw == 1) { // スイッチが押されたら 59 status = 2; // 停止へ。時間を表示したまま 60 delay = 0; // 再びスイッチ見ない期間開始 61 } 62 break; 63 64 case 2: // 停止。時間を表示したまま 65 if (++delay > NDELAY && mysw == 1) { 66 status = 0; // リセットへ戻る 67 delay = 0; // みたびスイッチ見ない期間開始 68 } 69 break; 70 } 71 72 // 5msec.毎に必ず次の桁を表示する、ダイナミック点灯 73 out7segled(time[digit], digit); 74 digit = (digit + 1) & 3; // 0, 1, 2, 3, 0 ... 75 } 76}

投稿2020/01/06 07:59

編集2020/01/29 14:10
rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rubato6809

2020/01/06 09:25

と答えた後で気づいたのだが、wait (0.001); で1msecを測れるのかな。 それなら wait(0.005); しながら回せば良いのでは。
退会済みユーザー

退会済みユーザー

2020/01/14 08:25

回答ありがとうございます。 プログラムもわざわざありがとうございます、、。 こちらのプログラムを用いてmbedで出力してみましたが、あまりうまくいきませんでした。。 改良頑張ってみます
退会済みユーザー

退会済みユーザー

2020/01/14 08:38

rubato6809様が書かれたプログラムに関して質問なのですが、 「int status = 0; // 0: reset, 1: count up, 2: stop 」 こちらの「// 0: reset, 1: count up, 2: stop」とはどこで定義されたのでしょうか、、?
rubato6809

2020/01/14 10:24

0, 1, 2 という値にした根拠なら、私が勝手に決めました。 ここの switch 文は3種類の動作(状態)を区別するために使っています。3つを区別できるなら 4, 5, 6 でも良いし 10, 100, 1000 でも良いのです。 ある状態(たとえばリセットされて 0000 が表示されている状態)から、スイッチを押したら、今度は時間を測る状態(表示がどんどん進む状態)に変化する、そういう状態の変化を示す変数が state です。この値が変化することを、状態遷移と呼びます。 3種類の状態を示す値として 0, 1, 2 を選びました。
rubato6809

2020/01/14 10:44

そもそも、7segLEDは4桁ありますか? あるなら、まず目的の数字(0でも5でも…)を、ひと桁だけで良いから、点灯できることを確認することから始めたらどうですか? どのポートを、どうすれば、どうなる、ということをひとつづつ確認するのです。 たとえば、「dig1(p21)〜dig4(p24)は、4桁ある7セグメントLEDの、どの桁(digit)を光らせるかを指定するポート」とは、私の推測でしかなくて、本当にそうなのか、正論理という想定は当たっているのか、などを、自分でプログラムを直しながら、段階的に確かめていったら良いと思います。私ならそうしますが。
guest

0

このコードは数字を表示させようとしてるのはわかりますが、意味のあることはしていなさそうです。

まずは、intの数値を入れて呼び出したら4桁の数字を表示させるような関数を作ることを目指せばどうでしょう

投稿2020/01/03 09:37

編集2020/01/03 09:37
y_waiwai

総合スコア87749

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/01/03 11:04

回答ありがとうございます。 intの数値を入れて呼び出すとはどういうことでしょうか、、知識不足で申し訳ございません。
y_waiwai

2020/01/03 11:24

まずは、7セグのLEDとマイコンをどのように接続してるんでしょうか。 どこかのサイトの記事を参考に接続してると思いますが、それならそこの記事に表示させるコードは載ってないでしょうか 提示されているコードでは全くはなしになりません。 まずは、(どこかはわかりませんが)参考にした記事通りに組んで、表示させてみてはどうでしょう
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問