ぷらこのきろく

メモとかテストとか備忘録とか

C言語ポインタの初級者用課題

あっちの方はちょっと休憩。

某所で、プログラムとC言語を勉強し始めた方がおられて、すごくがんばっておられる。
僕も負けてはいられないんだけど、その方向けにちょっとした課題のプレゼント。

その1:値を入れ替える関数を作ってみる

こんなプログラム。

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	int c;
	/* まず初期値を表示する */
	printf("a=%d, b=%d\n", a, b);

	/* ここから値を入れ替えてみる */
	c = a;
	a = b;
	b = c;
	/* 値がいれかわったかな? */
	printf("a=%d, b=%d\n", a, b);
	return 0;
}

即席で作ったからタイプミスとかあったらごめんなさい。適当に直して。
aとbの値が入れ替わる処理はこんな風に書けます。直接一気に交換する方法…もないことはないらしいんですが、
普通は、退避用の変数(この場合はcですね)をとって、入れ替えを行います。
ということで、この入れ替える処理を関数(名前はとりあえず"swap")にしてみましょう。
まず失敗例。

#include <stdio.h>
void swap(int a, int b)
{
	int c;
	c = a;
	a = b;
	b = c;
	return;
}
int main()
{
	int a = 10;
	int b = 20;
	int c;
	/* まず初期値を表示する */
	printf("a=%d, b=%d\n", a, b);

	/* ここから値を入れ替えてみる */
	swap(a, b);
	/* 値がいれかわったかな? */
	printf("a=%d, b=%d\n", a, b);
	return 0;
}

実行してみたらわかるけど、これは値が入れ替わらないのですね。
なんでかというと、main()関数のaとswap()関数のaは違うものなんです。bももちろん同じ。
そして、main()関数のaの「値」(この場合は10ですね)がswap()関数のaにコピーされて動くので、コピーされたものを入れ替えるだけではコピー元のmain()のaやbには影響はないのです。
そこでどうするか、ポインタなんですね。*1
ポインタで、main()関数のaやbという変数のアドレスの値を渡してあげて、そのアドレスの指す値を入れ替える、そういう関数を作ってください。

*1:マクロの話はとりあえずおいとく

ASOOVU USBで遊んでみる(2-1)

その2-1:割り込みを使おうとして失敗する

タイマ機能というものがあるらしい。時間をカウントして一定時間経ったら教えてくれたり時間を計ったりできるらしい。
その機能で、時間がたったら割り込みがかかって教えてくれるものがあるっぽい。
というわけで、割り込みを使おうと思いたった。

XC8のマニュアルを読むと、

void interrupt hoge(void)

と書くと、hoge()は割り込み関数として登録されるらしい。
ASOOVU USBで使われるPIC18F2550は、割り込み関数が二つ(優先度高と優先度低)使えて、それぞれ

void interrupt low_priority hoge(void)
void interrupt high_priority heke(void)

で、優先度低と高が使えるらしい。と、PIC18F2550のデータシートとXC8のマニュアルに書いてあった。

というわけで、何もしない(単にreturnを返す)だけの割り込み関数だけ作って、動かそうとしてみた。
・・・動かない。今まで動いていたmain()の中身が実行されない。
いろいろ試してみた。3日ぐらいかけて。関数の中身を変えてみたり、割り込み許可をしないようにしてみたり、コンフィギュレーションビットを確認してみたり。
で、確認できたのは、割り込み関数を定義すると動かなくなって、定義をコメントアウトすると動くようになる。

なんでだろう・・・と、ASOOVU USBの販売元のサイトからサンプルプログラムをダウンロードして確認してみた。bootload.hに

#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x1008
...
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
void Remapped_High_ISR (void)

とかかいてある。書いてあることは半分くらいしかよくわからないが、優先度高の割り込み関数が置いてあるアドレスが0x1008に再設定された、ということなのではないか。

mapファイル(プロジェクトのhexファイルが置いてあるディレクトリと同じ場所に、~.mapと書いてあるファイルがある)を確認する。
ちょっとしか意味はわからないが、このファイルには関数やグローバル変数などがどのアドレスに割り付けてあるかが書いてある。

サンプルプログラムのmapファイルの優先度高割り込み関数(だと思われるもの)は、確かに0x1008に割り付けられてる。
そして、自分が書いたプログラムのmapファイルを見ると、0x0008に割り付けられている。

ここで、データシートを見る。figure5-1にメモリのマップがある。やっぱり0x0008だよなぁ。。
でも、やってみるしかない。割り込み関数の割り付けを変えてみよう。。

MPLAB X IDEのプロジェクトを右クリックして、Propertiesを選択。
XC8 LinkerのカテゴリからAdditional optionsを選択。Extra Linker Optionsに

-L-preset_vec=1000h,intcode=1008h,intcodelo=1018h,powerup,init

と記述。
f:id:prizeout:20171225223504p:plain
あ、なんかmain()が動きだした。割り込み関数を使ってみよう、と、適当にタイマ0で割り込みを起こしてみたら、
ちゃんと割り込み関数を通った。
しかしなんで割り付けをデフォルトから変えないといけないのだろう。どこにその説明が書いてあるのだろう。
まあともかく、これで次はやっとタイマをまともに使える。
続く。

ASOOVU USBで遊んでみる(4)

その(4) :コード書いてコンパイル・書き込み・実行

コード確認

コードはこれだけ
f:id:prizeout:20171217162443p:plain
とりあえずメモ

9行目

ヘッダファイルインクルード。こないだの日記でコンフィグレーションビットの設定を出力したコピーペースト。中でxc.hをインクルードしている。

14~15行目

PORTBとLATBを0クリア。
前の日記の初期化例で調べたのをそのまま。

16行目

TRISBを0に設定。つまり、RB0~RB7を全部出力に設定。

18行目

while(1)で回す。組込み関係ではプログラムは終了しないのが常道らしい。つまりmain()関数のreturnはしない。

19行目

500ms待つ。これはXC(コンパイラ)が提供するマクロみたい。
xc.hから読み込まれるpic.hに*1

// NOTE: To use the macros below, YOU must have previously defined _XTAL_FREQ
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

って書いてある。
で、10行目で_XTAL_FREQを設定。設定する数は、マイコンの周波数。ASOOVU USBのマニュアルに製品仕様が書いてあって
内部動作周波数:48MHzと書いてある。ということで48000000を設定。
・・・あ、#defineの値を括弧でくくるの忘れてた。

20~25行目

LATB4をON/OFFする。僕はif~elseで書くけど多分別に~のビット反転使ってもいいと思う。たぶん。
LATBbits構造体や、先ほどでてきたPORTBやLATB、TRISBのレジスタなどはpic18f2550.hで定義されてる。

コンパイル

で、コンパイル
MPLAB X IDEのプロジェクト名を右クリックして、Buildを選択。
コンパイル結果はOutput欄に出力。
f:id:prizeout:20171217170238p:plain
BUILD SUCCESSFULLでビルド成功を確認。
次に、hexファイル(デバイスに書き込むためのファイル)の場所を確認。

書き込み

HIDBootLoader.exeを起動。「Hexファイル読み込み」で、先ほどできたhexファイルを読み込む。
ASOOVU USBのマニュアルに従って、デバイスのジャンパーピンをBOOT側に設定し、USBケーブルでPCにつなぐ。うまくいくとLEDが赤青にちかちかする。
そして「Hexファイル書き込み」。うまくいけば書き込み成功のメッセージが出る。

実行

バイスをPCから外し、ジャンパーピンをBOOT側からもう一方へ設定する。もう一度USBケーブルに接続する。
実行結果の動画(youtube)
めでたしめでたし

*1:XCのヘッダファイル群はインストールされたディレクトリ、デフォルトでは"C:\Program Files (x86)\Microchip\xc8\v1.44\include"にある

ASOOVU USBで遊んでみる(3)

その(3):データシートを見る

とりあえず今回は、LEDを光らせたり消したりすることを考える。

ポートの確認

ASOOVU USBのマニュアルの裏側に回路図が書いてある。(サイトからダウンロードもできる)
で、LEDの部分を見てみる。
f:id:prizeout:20171217121741p:plain
LED(青)は25番ポートとつながっているらしい。

データシートの確認

公式サイトからデータシートをダウンロードしてくる。
http://ww1.microchip.com/downloads/en/DeviceDoc/39632e.pdf
英語とか、426ページとか、中学以降英語は落ちこぼれで文章読んだりするのも苦手な僕は結構うんざりなんだけど*1
がんばって手抜き読みをしてみる。きっと図表が書いてあるにちがいない。。
可能な限り図表だけで読んでみよう。。

ピン配置図

pdfの4ページにピン配置図があった。
f:id:prizeout:20171217130346p:plain
25番ピンはRB4というらしい。

ブロック図

12ページにブロック図があった。
f:id:prizeout:20171217130942p:plain
RB4はPORTBにつながっているらしい。

ポート回路図

というわけで10章。IO Portの章。回路図を見る。
f:id:prizeout:20171217150310p:plain
三角形は3ステートバッファというものだと思う。論理回路:3ステートバッファ(1) | 東芝 半導体&ストレージ製品
制御信号に○がついてるからきっとNOTで、TRISラッチが0のときにDATAラッチからIOピンに出力があるらしい。
(ラッチはなんか値を保存しておくものだった気がする。なんか値を書き込んだらそのまま保持されるんだろう。)
ということでTABLE 10-3を見ると
f:id:prizeout:20171217152722p:plain
RB4はLATB4から読み込めるらしい。

初期化例

PORTBの初期化例が書いてあった。アセンブラなんか読めないが、この程度ならなんとなく理解。
f:id:prizeout:20171217153053p:plain
とりあえず理解に必要なのは上下の赤枠の中。真ん中のはコンフィグレーションビットの設定でしてあるからいらない。と判断。
上の部分はPORTBとLATBの0クリア。下の部分はTRISBに0xCFを代入。0xCFは2進法で書くと11001111だから、一番右を0番目、一番左を7番目として、4,5番目が0となっている。
コメントに、「RB4とRB5を出力に」とあるので、TRISBの該当ビットを0にすると出力なんだろう。

というわけで、やっとコードが書ける。
続く。

*1:だったら日本語訳見ろっていうんだけど、それはそれで敗北感が・・・

ASOOVU USBで遊んでみる(2)

その(2) :Configuration bitの設定

よくわからないけど、機械の設定っぽいことをするらしい。
本当はデータシートとか見ないといけないけど、そのうち詳しくなってみたい。

とりあえず今回は、マニュアルのサイト、あるいは書き込みソフトをダウンロードしたサイトから
適当なスケルトンソフトを落とし、中のヘッダファイルを見て真似してみた。

Production→Set Configration Bitsを選ぶ。
いろいろとあるので、とりあえず真似して設定。
f:id:prizeout:20171214010833p:plain
Generate Source Code to Outputボタンを押すと、アウトプットのコードができる。
これをコピーペーストでソースコードに貼りつけるみたい。

main.cにぺたぺた貼りつけるのもあるんだろうけど、僕はヘッダファイルを作ってそこに貼りつけた。

続く。

ASOOVU USBで遊んでみる(1)

その(1) :MPLAB X IDE プロジェクト作成

MPLAB X IDEを起動する。
File→New Project
Microchip EmbeddedからStandalone Projectを選択してNext
f:id:prizeout:20171214002435p:plain

今回使うICはPIC18F2550というものらしい。(マニュアルに書いてある)
というわけで、Advanced 8-bit MXUs (PIC18)からPIC18F2550を選択してNext
f:id:prizeout:20171214002432p:plain

Toolsのところはよくわからないけど、ネットで見た感じPICのときはPICkit3を選ぶらしい。
というわけでそうする。
f:id:prizeout:20171214002427p:plain

コンパイラはXC8
f:id:prizeout:20171214002424p:plain

最後にプロジェクト名を適当に決める。
encodingのところはWindowsはShift-JISなんかなということでそうした。今ならutf-8とかその辺なんだろうか。わかんないけど。
で、Finish
f:id:prizeout:20171214002420p:plain

これでプロジェクトは作成完了。
main.cがなければいかんだろうから、
Source Fileのところを右クリックして、New→main.c
f:id:prizeout:20171214002420p:plain

続く。

ASOOVU USBで遊んでみる(0)

その(0) :準備編

数か月前に買ったASOOVU USBというものをせっかくだからちょっとだけ起動してみようかと思ってやってみた。
ASOOVUシリーズ | Bit Trade One, LTD

まず、マニュアルに書いてあるサイトから書き込みソフトをダウンロードした・・・
のだが、僕のマシンのノートン先生がウィルスと判断し削除されてしまった。
どうしようかと思ったが、上にあげた販売元のリンクのサポートから書き込みソフトがダウンロードでき、そちらはウィルスでなかったらしく事なきを得た。
次に、
MPLAB- X IDE | Microchip Technology Inc.
ここからMPLAB X IDEとXC8をインストール。(以前インストールしてたが、最新版に更新した。)
また、今回遊ぶマイコンは16ビットマイコンだからXC16もインストール。
↑まちがい。PIC18F2550は8ビットらしい。でもなんかXC16を入れたらその後の設定がうまく通った気がする。

続く。