![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?5a7ff87)
PIC16F648Aのタイマ0割り込みによって定期的に1-Wireデジタル温度計のDS18B20と通信させるプログラムを作ろうとしています。DS18B20の通信ポートとはPICのRB7ポートと繋がっており、4.7kΩの抵抗によってプルアップされています。PICには内部クロックを使って4MHzで動作させています。
DS18B20に「1」を書き込むプログラムですが、初め入力の設定でHighにしてある状態から、出力のLowに切り替え、2μsだけ待ったあと、また入力に切り替えてHighにするプログラムを組んでいます。
しかし、その波形をオシロスコープで見てみると、Lowである時間が約35μsと異様に長くなっていて困っています。この時間はたとえ待ち時間を1μsにしても10μsにしても、待ち時間プログラムでなくNOP1回にしても変わりません。
ネットで調べたりもしましたが、このような事例は僕が調べた限りでは載っていませんでした。これだけの質問内容ではご回答しにくかったら申し訳ありませんが、誰かわかる方ご教授いただけると助かります。
No.2ベストアンサー
- 回答日時:
私もPICのことは全く知りませんし、レジスタの説明がないのでプログラムも斜め読みですが、…。
一つ言えることは、一般的に高々4MHzのCPUクロックで1µsクラスの分解能を持たせるのは無理ではないかと思います。
4MHzは1クロック0.25µsであり、1CPU命令0.25µsで実行していると考えられるので、
コンパイルの結果1行が4CPU命令とかになった場合、容易に1µsの遅延が入ります。
PICの周辺機能のアーキテクチャのことはよく解りませんが、IOレジスタのリードライトに数クロックかかる場合もあります。
if文でIOポートレジスタにアクセスしているようですが、レジスタアクセスとテスト判定、ジャンプなどで数クロック消費していると思います。
これだけで1μs位は容易に遅延します。
さらに__delay_usとかいう関数をコールしていますが、この処理にもかなり時間がかかると思います。
関数コールにはプログラムカウンタやレジスタの待避、引数のプッシュとか重い動作が関わるので、
軽く数μs~数十µsとかは遅延すると思います。
なので、コールとリターンで20μs~数十μsレベルの遅延は考慮すべきです。
ゆえに35μsは想定内ではないかと思います。
すなわち、__delay_us関数で数十μs以下の時間調整は困難だと思います。
もう一点、コンパイルの最適化はどのようにしているのか書かれていませんが、高度な最適化をしているとNOPは削除されかもしれません。
なので、NOPの挿入で確認しようというのは適切ではありません。
これらの観点についてコンパイラがどのようなコードを出力したかアセンブラレベルで注意深く検討する必要があります。
後、考えられる点としては、PICのRB7なるポートのドライブ能力がDS18B20のキャパシタをフルスイングするだけの能力があるのかという点も調べる必要があるかもしれません。
No.4
- 回答日時:
小生コンパイラはやったことはありませんがPICのアセンブラは経験があります。
ご質問の症状は経験がありませんが、可能性がありそうな点がいくつか思い当たります。
1.クロックは4MHzとのことですが、内部発振周波数ですか? φ/4が4MHzですか?
内部発振が4MHzではシステムクロック(φ/4)は1HMzのはず。ならば 1命令=1μSec になます。完全マシン語でギリギリの速度ですね。コンパイラではまず無理と思いますが。
2.コンパイラは一般に1行済むごとにAcc(PICではW?)を退避してシステムの進行を確認しているはず。そんな仕様のコンパイラではないですか? 当然退避、復旧に時間を要しますね。少なくともこの部分はマシン語でないと無理と思います。
3.割り込みを使っていますね。このポート制御の前後では割り込みは禁止にしていますか?
このCPUのハードウェアは調べていませんが一部のチップではどのピンからでも割り込みが掛けられます。出力に指定しておいてもレベルが変化するとそのエッジで割り込みが掛るものがあります。こんな割込みは使ってないですよね?
ご回答ありがとうございました。
1. クロック周波数である4MHzは内部発振周波数のことです。ご指摘の通り、コンパイラだとマイクロ秒単位の制御は難しいことがわかりました。ありがとうございました。
2. CコンパイラとしてMPLAB XC8 Compilerを使用しました。コンパイラの仕様に関して勉強不足で、1行済むごとにシステムの進行を確認しているのかどうかわからないので申し訳ありませんが、もしそのような仕様ならば、そのためにもマシン語を使う必要があることがわかりました。
3. 確かに割り込みを禁止することを忘れていました。PIC16F648AはポートBに割り込みを掛けられるそうです。その可能性も含めて改善していきたいと思います。
No.3
- 回答日時:
答えは既に出ていますが、一応PICを知っている者として補足しておきますと、
PICは1命令に4クロック掛かります。
ですから2μsは2命令です。
またIOレジスタの操作自体は1命令ですが、ワーキングレジスタにロードしてから書き込む必要があるのとバンク切り替えのせいで、3~6命令は掛かるかと思います。
PIC16F648Aでマイクロ秒単位の制御をしたいならアセンブラで書くしかありません。
アセンブラを覚える気がないのであれば、32MHzで動作するPIC16F1823などを使えばなんとかなるかもしれません。
なおポートのドライブ能力はPICはそれなりに高いので大丈夫でしょう。別のPIC(10F200)ですが直結でDS18B20を使ったことがあります。
ご回答ありがとうございました。
PIC16F648Aをマイクロ秒単位で制御するプログラムを、C言語で書くことの難しさを知ることができました。
回路の設計を変えたくないこともあるので、一度アセンブラでやってみたいと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- ダイヤルアップ Raspberry Piでアナログモデム経由で音声再生 1 2022/05/20 18:01
- Windows 7 更新プログラムを入れたら操作出来なくなりました(泣) 1 2023/02/26 11:04
- モニター・ディスプレイ Dell G2422HSのディスプレイの入力信号の切替器やリモコンを教えてください 4 2023/05/30 17:56
- その他(ビジネス・キャリア) グーグルの障害者訓練プログラム募集あるがどうだろ?6時間勤務で月収22万!! 1 2023/02/17 20:36
- その他(ソフトウェア) OMRON PLC CP2Eのプログラム 1 2022/11/24 10:57
- C言語・C++・C# [C言語] コメント文字列を無視して、数値データを読み込むプログラム部分について 5 2022/10/05 11:03
- その他(IT・Webサービス) 昨日今日と、Open AIのChat GPTを使ってみたのですが、正直言って、期待外れです… 返答内 4 2023/02/13 21:49
- その他(プログラミング・Web制作) プログラムの起動、利用について、使用期間を設定する方法 3 2023/08/06 21:03
- USBメモリー・SDカード・フラッシュメモリー 銀行が振込データの受け渡しに未だにFDを使っている理由は「FDDがAドライブ固定だから」って本当? 11 2022/06/02 03:53
- その他(コンピューター・テクノロジー) 50台の織機から回転数を取得・集計しモニターに表示したい 2 2022/11/05 15:48
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
PICの入出力切り替えの時間がプ...
-
SHマイコンについて
-
0xffffとは?
-
エクセルVBAのIf,Then 構...
-
8ビットのデータの、先頭ビット...
-
レジストってなんですか?
-
ライン数とステップ数の違いは?
-
ビットシフトってどんな時使うの?
-
コンピュータ言語とプログラミ...
-
PICのC言語でキャリーオーバー
-
[C言語→アセンブリ言語]はどう...
-
CASL(アセンブラ言語)に関する...
-
算術シフト演算が成り立つ理由...
-
Delphiでのメモリリーク検出
-
アセンブラからC言語に変換する...
-
シーケンサのデータレジスタD...
-
実行ファイルからソースはみれる?
-
CASLIIでかけ算
-
GCCの.cfi_系について
-
本気でマシン語を覚えたい
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
PICでパルス数をカウントする方法
-
PICでパルス数をカウントし、カ...
-
PICマイコンを使った分解能1μs...
-
C言語によるウェイト
-
マイコンのCCRのIビット
-
PICの入出力切り替えの時間がプ...
-
入力回数のカウントをする方法
-
シリアル通信のデータ受信につ...
-
H8を利用したPWMのパルス生成に...
-
PICでスピードメーターを作...
-
RTCの通信方法(I2C、S...
-
組み込みマイコンの誤動作について
-
H8/3069Rでパルス時間間隔測定
-
0xffffとは?
-
エクセルVBAのIf,Then 構...
-
8ビットのデータの、先頭ビット...
-
情報科学の飽和演算、ラップア...
-
ビットシフトってどんな時使うの?
-
ライン数とステップ数の違いは?
-
アセンブラからC言語に変換する...
おすすめ情報
省略や改変のあるプログラムとなってしまうので申し訳ありませんが、下記にプログラムを載せておきます。
#include <xc.h>
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = ON
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config CP = OFF
#define _XTAL_FREQ 4000000
int icount;
void ds18b20_read(void); // DS18B20と通信をする
void onewire_write(int data);
void main(void){
di();
// 76543210
T1CON=0b00110001; // bit0:TMR1ON 1 タイマ1の動作をする
// bit1:TMR1CS 0 内部クロック
// bit2:^T1SYNC 0 内部クロック同期
// bit3:T1OSCEN 0 外部発振回路不使用
// bit4:T1CKPS0 1 プリスケーラ (8)
// bit5:T1CKPS1 1 (同上)
// bit6:なし 0
// bit7:なし 0
// 76543210
TRISA=0b11100000;
TRISB=0b10000000;
PORTA=PORTB=0;
TMR1IF=0;
TMR1IE=1;
PEIE=1;
GIE=1;
while(1);
}
void interrupt ipt(void){
if(TMR1IF){
TMR1IF=0;
if(icount++>3){
icount=0;
ds18b20_read(); // DS18B20と通信をする
}
return;
}
}
void ds18b20_read(void){ // DS18B20と通信をする
di();
TRISB=PORTB=0; // リセットパルス
__delay_us( 500 );
TRISB=0b10000000;
__delay_us(70);
if(PORTB==0b10000000){ // 存在パルスの確認
TMR1IE=1;
PEIE=1;
GIE=1;
return;
}
__delay_us( 500 );
onewire_write(0xCC); // SKIP ROMコマンド
onewire_write(0x44); // CONVERT Tコマンド
}
void onewire_write(int data){ // DS18B20にデータを書き込む
int count;
for(count=0;count<8;count++){
if((data>>count)&0x01){ // 「1」を書き込む
TRISB=PORTB=0;
__delay_us(2);
TRISB=0b10000000;
__delay_us(70);
}
else{ // 「0」を書き込む
TRISB=PORTB=0;
__delay_us(70);
TRISB=0b10000000;
__delay_us(2);
}
}
}