ラベル PIC の投稿を表示しています。 すべての投稿を表示
ラベル PIC の投稿を表示しています。 すべての投稿を表示

2012年3月16日金曜日

HI-TECHでprintfとかscanf

PICでデバッグしたい時にいちいち定数を書き換えてコンパイルしなおして焼き直すというのは面倒ですよね
毎回上手に焼けましたぁってなるまで待つのもめんどくさいし

ってことで PICでscanfが使えれば便利

どうやって使うか
シリアルポートの場合
char getche(void) { while(!RCIF); return RCREG; }

void putch(unsigned char ch) { while(!TRMT); TXREG = ch; }
の2行を追加すればおk
STDOUTはputch
STDINはgetcheです
出力がchだからといって入力もchとは限らない
紛らわしい...

で 実際に使うには

普通にC言語のコンソールアプリと同じです
scanf("%d", &num);
でnumに整数を読み込んで
printf("%d\r\n", num);
でnumを文字列にして書きだす

ただまぁscanfとかの問題もそのまま残ってるはずなので
製品には使用しないほうがいいよなぁ
もっとも使う用途も思いつかないけど

↑のget/putはとにかく簡単に済ます方法なので
速度とかを優先するならこのコードではダメです

例えば9600bpsで通信した場合1バイト送/受信するのに1mS位かかります
これはかなりのロス
バッファとか割り込みとかを活用すれば
100バイトでもメインのコードは1mSかからずに処理できるので
ただそうすると割り込みやら色々めんどくさいんだよなぁ


とりあえず PICで数値とか読み取る方法
覚書でした

2012年3月15日木曜日

PIC18のスペック

PIC18だとUSB内蔵があります
で その簡単な見分け方

クロックの最高が48MHzだとUSB対応
楽ですね
でもまぁ僕はUSBとか使わないので意味無いですが…

PIC18FのDIPでも64MHz(16MIPS)っつー恐ろしいマイコンがあるみたい
28pinの300milなので缶サットにいいんじゃないかと 思ってるんですが
シリアルも2本あるのでXBee用とGPS用 みたいな
どうせ手元にないと調べる気も起こさないダメ人間なので
2個位買っちゃえばとりあえず使うかな

で 何がしたいかというと
PIC18F2550って値段高くね?
ってことなんですよ
で プログラムメモリとSRAMとEEPROMが2550の倍でクロックが1.3倍くらいでタイマも倍近いのに値段が半分の石 ってのが目の前におかれたら飛びつくしか無いじゃないですか
まぁまだ買ってないんで目の前には無いんですけど

でもなんか裏が有りそうだよなぁ…
クレイモアでも仕掛けて有りそうな感じの

でもそういうのがなければ結構よさそうな石です

-追記-
PIC18F2550が350円で売ってる
あれー? 前は500円くらいじゃなかったっけ?
2010年11月に買った時の納品書には400円って書いてあるから
50円値下げしたのかもしれないけど 前はもっと高かった気がするんだよなぁ…

2012年3月11日日曜日

1でdisなフラグの謎

PIC18F2550でRB0を入力として使ってた時にハマったおかしな点

ADON = 0; ADCON1 = 0;
としていて デジタル出力として正常に使えていたのでそのまま使っていた
そして入力として使おうとした時 なぜか常に0になる
んで データシート見て気がついた
ADCON1 = 0;ってアナログ入力じゃん

ええ 初期設定がアナログだから0にしてアナログをオミットかと思ったら
デジタルを有効にするために1を設定
なのね
PICって時々「1で無効にする」ってのがあるよね...
多分これ前も引っかかったよなぁ…

ということで PIC18F2550ですべてデジタルポートとして使う場合
ADCONbits.ADON = 0; ADCON1 = 0x0F;
というのが正解
ADCON1の下位4bitが0でアナログ 1でデジタルになる
上位2bitは無効 上位3-4がVREFで これは0で
なのでADCON1 = 0x0F;
詳しくは データシート265ページあたりの
"10-BIT ANALOG-TO-DIGITAL CONVERTER (A/D) MODULE"
を参照してくだされ

16Fのアナログ入力に慣れてると
18Fのアナログ入力は意外と厄介なので
使う場合はまずデータシートを見てください
16のように「好きなポートをアナログに」っていう設定ができないので

では
PICで前にもやらかしたバグを再発させたという恥さらし覚書でした

2012年2月26日日曜日

HI-TECHで再帰

どうやらHI-TECHでは再帰ができないらしい
まぁ組み込み用コンパイラならそれが妥当か

しかし
printf関数で%sはポインタ渡してなすがまま
という仕様で作ってたから
作りなおしだーよ

それにポインタを関数で渡しちゃったら
char text[] = "hello %d";
みたいなのが渡された時に困るからな
今回はforで\0まで出力

んで 現状10進での出力しか対応してないけど
やっぱ組み込みで使うなら2進も必要だよなぁ

ちなみにオリジナルのprintf関数で九九を出力させるコードは
ROM1399/RAM119くらい消費してる
結構重いよなぁ

そして いろいろいじってて気がついたのだけど
htc.hをインクルードするとstdio.hもインクルードされるのね
めんどくせぇよorz

つーことで
自分でprintf作っちゃうよぉ というお話でした
うーん 他に色々やることあるのに
優先順位低い方ばっかりやってるなぁ

2012年2月17日金曜日

C18

C18の最適化ってどれくらいなのかなぁと
おもって Standardを試してみたいんですが

確かインストール時にStandardかLiteか選べるようになってたはずなんだけど
選べない
でも ダウンロードリンクのアドレスが StandardとLite 同じ行き先なので
多分どっかで選択できるはずなんだけどなぁ…
(落ちてくるファイルの名前が微妙に違うんだけど 容量は同じ)


んで 実験環境がVirtualPCなんですけど
なんか変わった気がするなぁと思ったら
バージョン上がってるのね
8.83だそうです
Win7でいつも使ってるのは8.70
微妙にメニューが増えてる気がするから
バグ抜きとかだけじゃなくて機能追加もされてるんだろうな

そーいや MPLAB Xとかどうなったんだろう
PICKIT3に対応したら とか思ってたけど
べつにWinでも苦労してないのよねぇ
だって外出先でプログラムの変更とかしないし
(昨年2日連続で呼び出されてやったりしたけど その2回だけだし その時はBoot Campで対応)


で Standard版
どうやったら使えるんだろう



今作りたい関数の変数値は
動作中に変わることは無いので
コンパイル時に渡して計算してくれればいいな と
思ってるわけですよ

例えば
i = sum(50 + 100, 20 + 50);
みたいに呼び出したら
50+100と20+50は
150と70に置き換えられるわけじゃなく
プログラムの実行時に計算されるわけですが
中で多少複雑な計算をしているので
それだけで40usくらいの時間がかかります
(18F2550@48MHz動作)
だけど その処理はしたくないわけですよ
で 計算する値はコンパイル時には決まっているので
コンパイラが書き換えてくれるとありがたいわけです
(言い換えると 最悪の場合コンパイル毎に変化するので式は必須)

HI-TECHだと
for (i = 0; i < 10; i++) {
    __delay_ms(i);
}
みたいなコードはエラーになってしまうので
強制的にコンパイル時に計算 ってことは可能なのかもしれませんが
方法がわからない

HI-TECH独自の機能なのか
そうでなければC18でも可能なのか


まぁプログラミングは初心者とたいして変わらないくらいのレベルなので
僕が知らないだけという説が最有力なわけですが

インライン展開とか 興味あるんだけど
詳しく解説してるところが無いんだよなぁ


ま,いろいろ 探してみます

1個頼まれごと(?)があるんだけど
デバッグ環境がないとか 夏までは使う予定ないとか
色々な理由を作って放置してるんだよなぁ…
バグ修正でデバッグ環境が無い+原因不明 となるとやる気でないよなぁ…
せめてソフトウェアかハードウェアかだけでも切り分けられればいいんだけど
デバッグ環境が手元にないからそれもできないわけで...

2012年2月15日水曜日

メモリが120バイトしか使えない

PIC18Fって 大体のコードがC18を使っています

でも 僕はHI-TECHを使っていました

だけど そろそろC18使いたいなと思って
使い始めたんですが

なんと 変数が120バイト以上宣言できない

18F2550ですが
例えば
char c, d, buf[118];
は大丈夫で
char c, d, buf[119];
はダメです
また
int i;
char buf[118];
は大丈夫で

int i;
char buf[119];
はダメです

変数120個 じゃなくて メモリ120バイト が上限らしい
んで それを超えると

Error [1300] stack frame too large
っていうエラーが出てくる


んで ぐぐってみると まぁ 結構同症状が出てるらしい

なんかマニュアルに書いてあるっぽかったので

見てみたら
こんなことが書いてあった

E.1 ソースコード互換性
  E.1.1 スタックフレームサイズ
    コンパイラーは拡張モードで動作する時、ローカル変数の合計サイズは関数当り、
    96 バイトに制限されています。非拡張モードの場合は 120 バイトです
なるほど
どうやら1個の関数で使えるのは最大でも120バイトらしい
うーん…
文字列からデコードさせたいとかだと
受信用に100バイト位確保して いろいろカウンタつけると
ギリギリ って感じだよなぁ

ま グローバル変数はいくらでも宣言し放題らしいので
最悪それを使うとして


ところで

#include <p18f2550.h>
void main(void) {
for ( ; ; ) ;
}
っていうコードだけでメモリを270バイト近くも使うというのはどういうことなんじゃ?
C語ってそんなに重いコードなの?
んな訳ないよなぁ

いくら2550のメモリが広大だからといって2048バイトしか無い内の300バイトは痛いよ


つーことで
C18で120バイト以上メモリを確保できない><
という問題でした

1個の関数の中では最大120個しか使えないらしい
ま、それ以上使う方法もあるっぽいんだけど

2012年1月13日金曜日

PICで温度計 を作りたかった

PICで温度計を作りたかった
要するに作れなかった


PIC16F88を使って温度計をつくろうとしたんだが!が!

Q. なぜ作れないのか
A. HI-TECH Litteだから

HI-TECHのLiteって printf("%f", f);って書き方ができないんですよ
浮動小数点数の出力ができない
なので温度の計算ができない

↑の写真の149というのはADCから得られた数字です
0〜1023の間の149
大体室温は150±1くらいで安定してます
1は誤差のうちですね

んで ADCの結果からどういう計算をするのか
((((5/(2^10))*値)*1000)-500)/10
となります
暗算? 無理ッス
むしろファーレンハイト的な発想でいいじゃないかと
150なら室温 それ以下なら寒いかな それ以上なら暑いかな
ダメすか...


とりあえず USBシリアル変換をつないで
アナログ値をそのまま送り出そうかなとか思ってます
そしたら PC側で計算して
記録するなり
グラフにするなり グラフをFacebookに投稿するなり
いろいろできるはずなんですよ

とりあえず 温度センサをライターで炙ったらあっという間に300を超えるので
一応温度計としては動作しています


ちなみに 今回使ったセンサは以前にこのブログで紹介したものと同じなので
詳しくはそちらをどうぞ
↑↑↑の方の検索枠から「温度計」とか入れて探せばすぐ出るはず
その時はNetduino使ったんだよね
ふつーに浮動小数点数が扱えるし

しかし 浮動小数点数使えないとなるとどうするかなぁ…
まぁ 方法はいくつかあるのですけどね
やっぱめんどくさいのですよ

実験用の基板

このPIC↓ 16F88なんですけど 仕事で急に必要になってRSで買ったんですよ
すげぇなおい
こんな梱包始めてみたぞ
プラスチックケースに入ってます
1/10インチ間隔でデコボコになってるのでピンが曲がる心配も少ない というもの
無駄にたけーと思ったら...

んで 作ったのが↓


液晶と ADCを実装する予定
ADCは内臓のを使うけど

んで 一番アレなのがここ↓

まんなかにチップ抵抗があるでしょ
これ3個積んであるんですよ…
LEDの丁度良い制限抵抗がなかったので 4.7kを3個重ねました
1.5kΩ 3/10Wの抵抗となりますw

今回は12V入力にしました
いつもは5Vの電源を使うんですけどね
なんとなく 気分で
レギュは定番7805 3本の足の間にチップコンデンサが2個入ってたりしますが
まぁ「とりあえずつないどきゃ大丈夫でしょ」で作ってるので
本当はどういうふうに作るべきか知らないのですよ
あっ 電解コンデンサも47uFが1個ずつついてますよ

とりあえずまずは液晶の配線をつないで
そのあとでADCの実験
ADCなんて2回くらいしか使ったこと無いorz


ちなみに
缶サットは 電源用にPIC16F88を1個乗っけようかと思ってます
電源の電圧監視とか その他もろもろで
でも PICのADCって1024段階じゃないですか
電池はNi-MH4セルなんですけど 充電時には12V近くかかるので
1/3くらいに分圧したいわけですよ と言うことは分解能も1/3になるわけです
分解能14.64mVくらい?
-ΔVが1セルあたり5〜10mVくらいらしいので
全然分解能足りないのですよ
どうしたらいいんですかねぇ...
mbedの分解能は恐ろしい物がありますけど 実際にその分解能があるのかな…

例えば 12bitADCというのがあるんですよ マイコンっていうか半導体
6pinパケで2ch入って600円くらい
12bitだと 0〜5V 分圧1/3としたばあい
分解能3.66mVくらいになるんですよ これならまぁなんとかなるか というくらい
ギリギリですけどね
で 外部にADCを使うなら 16F88を使う理由が無いんですよ
なるべく小型化したいので8pinPICでいいじゃないですか
実際は追加機能とか考えると8pinじゃ無理な気もしますが
ADC2個とFET2個あればいいのでね
ADCのIF次第では 8pinのPCIでもいいかもしれません
(ただ普通の8pinだとIOが5本しか無いので かなりキツイ)

ということで 今回はココらへんで

2011年10月25日火曜日

PICで高速にシリアル通信

PICでpurintfを使う場合
普通は

void sputch(const char ch) {
while(!TXSTAbits.TRMT);
TXREG = ch;
}
っていう関数を使うことになる
これはシリアルで文字列を送信するためのものなんだけど
9600bpsだと1bitあたり
1/9600*1000000で104uSかかる
それが8bit+2(スタートストップ)で
1バイト送信するのに1mSくらい
ということは30文字送信するのに30mSかかる
これは無視できない時間

ということで
割り込みで送信できるようにしてみた


char text[50];
char textSize;
char textCnt = 0;



static void interrupt intr(void) {
if (TXIF) {
if (textSize > textCnt) {
TXREG = text[textCnt];
textCnt++;
} else {
textCnt = 0;
TXIE = 0;
}
}
}

これで


void main(void) {
init();

textSize = sprintf(text,"hello world ... serial TEST\r\n");
TXIE = 1;

for ( ; ; ) {
}
}
とかだと 300uS程度で処理が完了する
あとは割り込みで勝手に送信してくれる


ただ 当たり前だけどこれはハードウェアシリアルが有るPICに限られます


2011年10月11日火曜日

みろ!電子部品がゴミのようだ!


「摂氏−30℃でも動作可能なシステム」に液晶使うわけにもいかないので
とりあえずLED作ってみた
意外と暗い
抵抗値は20Ω程度でもいいみたいだけど47Ωにしておいた
まぁ極端に言っちゃえば抵抗なんてなくてもいいんだけど
(2mS程度で切り替えてるから デューティ比は12%程しか無い)

裏↓

みろ!基板がゴミのようだ!

凄い酷い所で3層になってる
チップ抵抗は9個使用
LEDの制限用に47Ωが8個
プルアップ抵抗に47kΩが1個
本当はもう一箇所プルアップしたかったけどやめた

LED側↓
これは4桁程度なら仕事で4個前後作ってるから
いつもどおりって感じ
さすがに8桁は初めてだけどw
配線は70本超えてるはず

まぁ… 二度と作りたくないっすね


制御には18F2550を使ってる
一応チップコンデンサならGNDに入れられるからUSB接続もできるw
まぁUSARTっすけどね…
かなり余裕ある と言うかこの程度であのROMがキツキツになるならいったいどんな処理してるのか気になる
もうちょっと機能追加してみて だな
ICSPコネクタが無いからデバッグは大変

2011年9月20日火曜日

【追記】LCDモジュールに外字登録

追記
 このコードとんでもないバグを抱えてるらしい
 壊れはしないと思うけど なんか怪しい
 ということで↓のコードは使用禁止
 できれば今日中に修正コード書きます
 が 明日朝早いので無理だったら来週まで更新できませんorz
 (水曜日~土曜の4日連続で早朝出発のイベントが...)
******************************************************

マイコンで制御できる液晶モジュール(*)に外字登録を試してみたよ

今回作った関数はこれ↓
/* *** */

void LCD_Cset(char addr, char ca[]) {
LCD_8set(0x40 + addr, 0);
putch(ca[0]);
putch(ca[1]);
putch(ca[2]);
putch(ca[3]);
putch(ca[4]);
putch(ca[5]);
putch(ca[6]);
putch(ca[7]);

LCD_clear();
}

/* *** */
使い方は
/* *** */

const char data[] = {
0b00000000,
0b00000100,
0b00000100,
0b00011111,
0b00000100,
0b00000100,
0b00011111,
0b00000000 };
LCD_Cset(0, data);

/* *** */
みたいな感じで
でも配列を使うと結構コストが高いから
配列を使わないようにしてもいいかも

putchはHI-TECHでprintf関数を使えるようにするためのもの
簡単に言うとRSを1にして1byte送信

表示する場合はaddrで指定したアドレスをRSを1にして送信すればいいです

外字登録って結構便利で
ゲームを作ってる人とかカレンダーを作ってる人もいるみたい
あとおっきな文字を表示することもできるらしい

注意点としては外字は8文字までしか登録できないみたい
8文字を超えて登録しようとした時の処理とかは書いてないから各自注意してください


ということで 覚えておくとちょっと便利な小ネタでした

*これとかこれで動作確認をしたよ

2011年9月15日木曜日

DIPスイッチを使うよ

今回はDIPスイッチの基本的な使い方を解説するよ



回路は↓これ
どっか間違ってる気もするので参考程度に
DIPSWの左側がプルアップ抵抗 今回は470Ωを使ったけど本来はV+に直結するべき
DIPSWの右側はプルダウン抵抗 4.7kΩを使ったよ
基本的にこれだけで使える
スイッチがOFFだとPICはLになりスイッチがONだとPICはHになる
一般的にはプルアップしてスイッチを押すとLになるけど
今回はわかりやすいように(+後々簡単なように)アクティブHにした

そしてコードは↓これ
/* *** */

#include <htc.h>

__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_OFF & LVP_OFF & DEBUG_OFF);

#define _XTAL_FREQ 20000000
#define TXP RC6

void send(char);

void main(void) {
TRISC = 0x0F;
PORTC = 0;
TXP = 1;

char data = 0;

while(1) {
if (data != (PORTC & 0x0F)) {
send(0x08);
data = (PORTC & 0x0F);
send(data + (data > 9 ? (0x37) : ('0')));
}
__delay_ms(5);
}
}

void send(char ca) {
TXP = 0; __delay_us(100);
TXP = ((ca >> 0) & 1); __delay_us(100);
TXP = ((ca >> 1) & 1); __delay_us(100);
TXP = ((ca >> 2) & 1); __delay_us(100);
TXP = ((ca >> 3) & 1); __delay_us(100);
TXP = ((ca >> 4) & 1); __delay_us(100);
TXP = ((ca >> 5) & 1); __delay_us(100);
TXP = ((ca >> 6) & 1); __delay_us(100);
TXP = ((ca >> 7) & 1); __delay_us(100);
TXP = 1; __delay_us(100);
}
/* *** */

一応
5ms毎にスイッチを監視し変更があればASCII16進に変換してバックスペースと共に送信
という感じ
これはぼくが作ったLCDモジュールの仕様によるもので
バックスペース(0x08)→1行目1文字目に移動
ENTER(0x13)→2行目1文字目に移動
ESC(0x1B)→表示クリア
になってるから


今回はこれ以外に機能を付けなかったから通常のポート使用量だけど
気が向いたらもうちょっと少ないポート数で使えるような工夫も紹介するかも

2011年9月9日金曜日

PICでLチカ【改】

#include <htc.h>
#include <config.h>

#define _XTAL_FREQ 20000000

#define LED RB5

void main(void) {
TRISA =   0b000000;
TRISB = 0b00000000;
TRISC = 0b00000000;
PORTA = 0;
PORTB = 0;
PORTC = 0;

while(1) {
LED = !LED;
__delay_s(1);
}
}

コンフィグをヘッダにすることで移植を楽にした

自分は現状88と873Aしか使ってないから

#if defined(PIC16F88)
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#endif

#if defined(PIC16F873A)
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#endif
みたいな感じになってる

これでプロジェクトを作るときに選択した石のコンフィグが作られる
まぁ「典型的なコンフィグ」しか設定できないけどね
ちょっと動作確認したいだけならこれでも大丈夫だと思う

2011年9月5日月曜日

PICで液晶

/* *** */

#include <htc.h>

__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & BOREN_OFF & LVP_OFF & DEBUG_OFF);

#define _XTAL_FREQ 20000000

#define E RB0
#define RS RB1
#define RW RB2

#define D4 RA3
#define D5 RA2
#define D6 RA1
#define D7 RA0

void LCD_init(void);
void LCD_clear(void);
char LCD_printf(char text[]);
void LCD_8set(unsigned char, char, char);
void LCD_4set(unsigned char, char, char);

static void interrupt intr(void) {
if (RCIF) {
RCIF = 0;
char c = RCREG;
if (c == 0x1B) { LCD_clear(); return; }
if (c == 0x08) { LCD_8set(0x80, 0, 0); return; }
if (c == 0x0D) { LCD_8set(0xC0, 0, 0); return; }
LCD_8set(c, 1, 0);
}
}

void main(void) {
TRISA = 0b000000;
TRISB = 0b00000000;
ANSEL = 0;
PORTA = 0;
PORTB = 0;

LCD_init();

LCD_printf("LCD init ok...");
__delay_s(1);
LCD_clear();

for(;;) {
LCD_printf("hello");
__delay_s(1);
LCD_clear();
__delay_ms(1);

LCD_printf("world");
__delay_s(1);
LCD_clear();
__delay_ms(1);
}
}

void LCD_init(void) {
__delay_ms(15);

LCD_4set(0x30, 0, 0);
__delay_ms(5);
LCD_4set(0x30, 0, 0);
__delay_ms(1);
LCD_4set(0x30, 0, 0);

LCD_4set(0x20, 0, 0);

LCD_4set(0x20, 0, 0);
LCD_4set(0x80, 0, 0);

LCD_4set(0x00, 0, 0);
LCD_4set(0x80, 0, 0);

LCD_4set(0x00, 0, 0);
LCD_4set(0x01, 0, 0);

__delay_ms(2);

LCD_8set(0x06, 0, 0);

LCD_8set(0x80, 0, 0);

LCD_8set(0x0C, 0, 0);
}

void LCD_clear(void) {
LCD_8set(0x01, 0, 0);
__delay_ms(1);
LCD_8set(0x0C, 0, 0);
}

char LCD_printf(char text[]) {
char c;
for (c = 0; text[c] != '\0';c++)
{ LCD_8set(text[c], 1, 0); }
return c;
}

void LCD_8set(unsigned char data, char RSb, char RWb) {
LCD_4set(((data << 0) & 0xF0), RSb, RWb);
LCD_4set(((data << 4) & 0xF0), RSb, RWb);
}

void LCD_4set(unsigned char data, char RSb, char RWb) {
RS = RSb;
RW = RWb;
D4 = ((data >> 4) & 1);
D5 = ((data >> 5) & 1);
D6 = ((data >> 6) & 1);
D7 = ((data >> 7) & 1);

__delay_us(500);
E = 1;
__delay_us(1000);
E = 0;
}
/* *** */

PIC16F88 @ 20MHz
液晶との接続はコード最初のほうで確認してください
あと__delay_s()の追加をしてない人は
__delay_msに修正するなり
#define __delay_s(sec) { __delay_ms(sec * 1000); }
とか書き足すなり(動作確認はしてないけど)
適当に対応してください


実はこれARMチャレンジャーの液晶の動作確認に作ったコード
なぜかARMからだと動作してくれなかったので
PICで動作確認
んでこのコードをARMに移植しても動かないんだよね…
LCDの電源が5VでARMが3.3Vだからとかいうくだらない理由でも無いと思うんだけど…
何なんだろう

2011年9月4日日曜日

手っ取り早くPICでデバッグするためのUSART

/* *** */

void send(unsigned char data) {
TXP = 0;
__delay_us(100);
TXP = ((data >> 0) & 1);
__delay_us(100);
TXP = ((data >> 1) & 1);
__delay_us(100);
TXP = ((data >> 2) & 1);
__delay_us(100);
TXP = ((data >> 3) & 1);
__delay_us(100);
TXP = ((data >> 4) & 1);
__delay_us(100);
TXP = ((data >> 5) & 1);
__delay_us(100);
TXP = ((data >> 6) & 1);
__delay_us(100);
TXP = ((data >> 7) & 1);
__delay_us(100);
TXP = 1;
}

/* *** */

出力するポートを予め
#define TXP RA4
みたいに定義しておく必要があります
あと__delay_usを使うためにhtc.hもインクルードする必要があります
それと↓みたいにコンパイラに動作クロックを指定する必要があります
#define _XTAL_FREQ 20000000 // 動作クロック20MHz

ということで内部クロックを使って動作周波数が可変とかだと無理です
そういう時はdelay関数自分で作ってください


とりあえずこれだけで9600bpsで一文字送信はできます

2011年8月19日金曜日

C語高速化のコツ

ちょっと気になったのでメモ

たとえば
byte data[8,8];
っていうのがあったとして そこにデータを入れたい場合 一番手っ取り早いのは


char x, y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
data[x, y] = ((関数の引数[x] >> y) ? 1 : 0);
}
}

みたいなかんじのコードが楽
だけど PICの場合かなり高コストになっちゃう
ということで 実行速度をなるべく早くしたいなら


char x;
for (x = 0; x < 8; x++) {
data[x, 0] = ((関数の引数[x] >> 0) ? 1 : 0);
data[x, 1] = ((関数の引数[x] >> 1) ? 1 : 0);
data[x, 2] = ((関数の引数[x] >> 2) ? 1 : 0);
data[x, 3] = ((関数の引数[x] >> 3) ? 1 : 0);
data[x, 4] = ((関数の引数[x] >> 4) ? 1 : 0);
data[x, 5] = ((関数の引数[x] >> 5) ? 1 : 0);
data[x, 6] = ((関数の引数[x] >> 6) ? 1 : 0);
data[x, 7] = ((関数の引数[x] >> 7) ? 1 : 0);
}

とかのほうが 早くなると思う

まぁ場合によって多少違うだろうけど
forをネストすると実効速度がどんどん遅くなる っていう感じらしい

"ループ文同士での入れ子はループ文を多用するために、プログラミングのミスによるバグの一つである無限ループが発生しやすくなる。"
ということらしいので
やっぱなるべくネストはしないほうがいいらしい

16F88でLチカ

/* ** */

#include <htc.h>

__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & DEBUG_OFF);

#define _XTAL_FREQ 20000000

#define LED RB4

void main(void) {
TRISA =   0b000000;
TRISB = 0b00000000;
ANSEL = 0;
PORTA = 0;
PORTB = 0;

while(1) {
LED = !LED;
__delay_s(1);
}
}
/* ** */
はい
↓のポストのコードを実際に使うためのコード

このコードでは外部20MHzクロックで
RB4に接続したLEDを点滅させる

だけ

【メモ】HI-TECHでウエイト処理

htc.hをインクルードして
#define _XTAL_FREQ 20000000
をコードに追加
20000000はクロック この場合20MHzね
そしてコードで
__delay_ms(10);
ってやったら10mS待ってくれる
__delay_us
ならマイクロ秒で

そしてついでだから
pic.hに
#define __delay_s(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4.0)))
を追加してみた
これだと秒単位でウエイトができる
20MHzだとして最大で800秒分ちょっと
たぶんusでもmsでもsでもおなじはず


あとWin6.x(Vistaとか7)の場合普通はUACでpic.hを書き換えはできない はず
とりあえず自分はVisualC++を使ってるから 右クリックから 管理者として実行 で起動しておいた

とりあえず
メモ

2011年8月18日木曜日

【メモ】PIC16F88でUSART(受信割り込み)

/* *** */

#include <htc.h>

__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & DEBUG_OFF);

static void interrupt intr(void) {
if (RCIF) {
char t;
RCIF = 0;
TXREG = 'R';
t = RCREG;
RB4 = (t == '0' ? 0 : 1);
}
}

void main(void) {
TRISA = 0b000000;
TRISB = 0b00000100;
ANSEL = 0;
PORTA = 0;
PORTB = 0;

RCIE = 1;
PEIE = 1;
GIE = 1;

TXSTA = 0x20;
RCSTA = 0x90;
SPBRG = 32;

TXREG = 'S';

while(1) {
}
}
/* *** */

とりあえず動作確認だけだから無駄なコードとかあるかも
ハードUSARTなので回路図は省略
とりあえずTXとRXを間違えずに接続してください
あとRB4にLEDを1kΩくらいの抵抗を介してGNDに接続すると
数字の0(アスキーコード49だったかな?)で消灯
それ以外で点灯します
シリアル受信割り込みで処理してるから他の命令を実行中でも動作すると思う

とりあえずメモ程度なので変なバグあっても怒らないでorz
(バグ見っけたらコメント等で教えていただけると)

追記:動作クロックは20MHzです

(includeのあとが表示されない問題を修正 HTMLタグと間違われてたらしい バックスラッシュとかで"<"とかを無効化できたはずなんだけどどうやるんだっけ… 2011/08/19)