Skin:
[NORMAL]
[BLUE] [DOS] [LIGHT]  / コピーするための表示 / 実行
このファイル: /home/web6047/www/cgi-bin/prj/photos of index/20200809-/softwarei2c_2.c
1 //もとのプログラムの作成者 mit.ueno 様
2 //もとのプログラムについて思うこと:
3 //掲載ページが綺麗
4 //訪問者用に整えているのが良い
5 //現状説明のコメントが用意されていて良い
6 //「この設定をするとうまく動作しない」とコメントアウトして情報を残しているのが良い
7 //I2Cという技術仕様が示す信号の通りに信号を作るにはこうすればよい、というのがI2C_start()などで示されていて、学ぶことができました。ありがとうございます。
8 //
9
10 //今回使用した小型液晶用に、一部修正させていただきました。
11
12
13 //コメントは、古いまま直していない場合(私)があり、ざっと見直して直したものの、どこまで正しいかは検証していないので、読む方は気を付けてください。
14
15 /*
16 そのほかの情報:
17 この小型液晶はI2Cの送信のみで、受信はack信号(指示に対する了解という信号)しか受信しません。
18 そのため受信に関する関数は 未使用 のコメント以降に置いてあります。
19 I2Cに関して、元のページでも完ぺきな対応ではないとおっしゃっています。元のページの注意書きも参照ください。
20 */
21
22 #include "pic.h"
23 #include "stdio.h";
24
25 // CONFIG1
26 //http://rikei60.web.fc2.com/toybox/sokkyo/16F88conf.htm
27 //#pragma config FOSC = INTOSCIO //内部クロック発振。RA6,7は通常の入出力ポート。
28 #pragma config WDTE = OFF //暴走自動停止なし。
29 //#pragma config PWRTE = ON //電源立ち上げ時遅延スタートあり
30 //#pragma config MCLRE = ON //RA5はMCLR機能で、負パルスでリセット
31 //#pragma config BOREN = ON //電圧低下(>4V)リセット許可
32 #pragma config LVP = OFF ///MCLR端子に高電圧(VPP)を与えて書き込む。RB3(PGM)は通常の入出力ポート。
33 //#pragma config CPD = OFF //EEPROM読み出し禁止
34 //#pragma config WRT = OFF //フラッシュプログラムメモリ書き込み防止なし
35 //#pragma config CCPMX = RB3 //RB3コンパレータ入力
36 //#pragma config CP = OFF //プログラム読み出し許可
37
38 // CONFIG2
39 //#pragma config FCMEN = OFF //非常用内蔵クロック(FRC)使用禁止
40 //#pragma config IESO = OFF //電源立ち上げ時非常用内蔵クロック(FRC)使用禁止
41 //__CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & IESO_OFF & LVP_OFF);
42
43 #define I2C_SCL RB4
44 #define I2C_SDA RB1
45 #define I2C_SDA_TRIS TRISB1
46
47 //小型液晶アドレス(I2Cフォーマット)
48 #define LCD_ADDR 0x7C
49
50
51 static void I2C_start(void);
52 static void I2C_send(unsigned char);
53 static unsigned char I2C_ackchk(void);
54 static void I2C_acksnd(void);
55 static void I2C_nacksnd(void);
56 static unsigned char I2C_rcv(void);
57 static unsigned char I2C_rcv_char(unsigned char EE_P0 ,unsigned char addr1 ,unsigned char addr2);
58 static void I2C_stop();
59
60 static void wait_50us(void);
61 static void wait_1ms(void);
62 static void wait_ms(unsigned int);
63
64
65 //---from:
66 //lcdClr()
67 //main()
68 static void I2C_snd_char2( unsigned char databyte) {
69 I2C_start();
70
71 I2C_send(LCD_ADDR); // スレーブアドレス
72 if (I2C_ackchk()) {
73 }
74
75 //4. (液晶仕様:コントロール部)をスレーブへ送信する
76 I2C_send( 0b00000000 ); //液晶仕様:コマンド送信時 RSビット=0
77 if (I2C_ackchk()) {
78 }
79
80 //6. (液晶仕様:データ部)をスレーブへ送信する
81 I2C_send(databyte);
82 if (I2C_ackchk()) {
83 }
84
85 I2C_stop();
86
87 wait_ms(5); //これは必要。消すと1文字目が表示されない
88 return;
89 }//I2C_snd_char2()
90
91
92 //---from:
93 //main()
94 void lcdClr() {
95 I2C_snd_char2( 0x01 );//clear disp
96 }
97
98
99 //---from:
100 //main()
101 void lcdStr( char *str ) {
102 I2C_start();
103 I2C_send(LCD_ADDR); // スレーブアドレス
104 if (I2C_ackchk()) {
105 }
106
107 while( *str != '\0' ) {
108 //control byte
109 if( *( str + 1 ) == '\0' ) {
110 I2C_send( 0b01000000 ); //最後の文字を送信する際は、Co ビットをオフ(連続送信の終了を伝える)
111 } else {
112 I2C_send( 0b11000000 ); //最後の文字以外を送信時は、Co ビットをオン(start,stopを1回だけにして連続送信、という液晶の機能)
113 }
114 //ack
115 if (I2C_ackchk()) {
116 }
117
118 //data byte
119 I2C_send( *str );
120
121 //ack
122 if (I2C_ackchk()) {
123 }
124
125
126 str++;
127 }
128 I2C_stop();
129 }//lcdStr()
130
131
132 /* 参考になったURL(おもにアセンブラ学習に関して)
133 http://mitt.la.coocan.jp/pic/xc8/xc8_88_01_1.html もとになったファイル。I2C制御
134 http://mitt.la.coocan.jp/pic/pic42.html PICの命令とアセンブラ命令
135 https://maku77.github.io/memo/pic/asm/bank.html バンクについての説明
136 http://zattouka.net/GarageHouse/micon/MPLAB/Delay/Delay.htm CとインラインASMの変数の受け渡し例
137 https://www.buildinsider.net/small/netduino/05 I2C送信フォーマット図示など
138 */
139
140
141 volatile persistent unsigned char kekka; //アセンブラ学習用変数
142
143 int main() {
144 OSCCON = 0x70; // INTOSC 8MHz
145 ANSEL = 0x00; // AN未使用
146 TRISA = 0xF0; // RA0-3:out
147 TRISB = 0xE3; // RB2-4:out SDAは通常input(開放)
148 PORTA = 0x00;
149 PORTB = 0x12; // SCL=1,SDA=1
150
151 // SSPCON = 0x2B; // SSP enable & I2C Firmware Controlled Master mode
152 // この設定をするとうまく動作しない
153
154 wait_ms( 500 );
155
156 //液晶初期設定
157 I2C_snd_char2( 0x38 );//norm func---------------
158 I2C_snd_char2( 0x3d );//ext. func---------------
159 I2C_snd_char2( 0x1d );//osc freq
160 I2C_snd_char2( 0x52 );//power/icon/contrast
161 I2C_snd_char2( 0x6b );//follower ctr***
162 I2C_snd_char2( 0x70 );//contrast
163 I2C_snd_char2( 0x39 );//norm func---------------
164 I2C_snd_char2( 0x0f );//disp on/off
165 lcdClr();
166
167 //============================================↓↓↓アセンブラ学習用
168
169 lcdStr( "Asm P63" );
170 I2C_snd_char2( 0xc0 );//液晶画面2行目の先頭へ
171
172 /*
173 SAMPLE START ;0
174 LD GR0,DATA1 ;1
175 LD GR1,GR0 ;2
176 SUBA GR0,GR1 ;3
177 RET ;4
178 DATA1 DC 100 ;5
179 END ;6
180 */
181
182 #asm
183 GR0 EQU 0 ;
184 GR1 EQU 0 ;
185 DATA1 EQU 100 ;5
186 MOVF DATA1 ;1
187 MOVWF GR0 ;1
188 MOVF GR0 ;2
189 MOVWF GR1 ;2
190 MOVF GR1 ;3
191 SUBWF GR0,1 ;3
192
193 ;------結果表示用------
194 MOVF GR0
195 MOVWF _kekka
196 #endasm
197
198 //結果表示
199 char buf[15];
200 sprintf( buf, "%d", kekka );
201 lcdStr( buf );
202
203 //============================================↑↑↑アセンブラ学習用
204
205
206 while(1) {
207 }
208 }//main()
209
210
211 //---from:
212 //I2C_snd_char2()
213 //lcdStr()
214 static void I2C_start() {
215 //START condition作成
216 I2C_SDA = 1;
217 I2C_SDA_TRIS = 0; // output
218 I2C_SCL = 1; // SCL high
219 NOP();
220 NOP();
221 NOP();
222 NOP();
223 I2C_SDA = 0; // SDA low : startA
224 NOP();
225 NOP();
226 NOP();
227 NOP();
228 I2C_SCL = 0; // SCL lowB
229
230 return;
231 }
232
233
234 //---from:
235 //I2C_snd_char2()
236 //lcdStr()
237 static void I2C_stop() {
238 //STOP condition作成
239 I2C_SDA = 0; // SDA low
240 I2C_SDA_TRIS = 0; // output
241 I2C_SCL = 1; // SCL high
242 NOP();
243 NOP();
244 NOP();
245 NOP();
246 I2C_SDA = 1; // SDA high
247 // I2C_SDA_TRIS = 1; // input(SDA high) : stop
248 return;
249 }
250
251
252 //---from:
253 //I2C_snd_char2()
254 //lcdStr()
255 static void I2C_send(unsigned char send_data) {
256 unsigned char i2c_data,i;
257
258 I2C_SDA_TRIS = 0; // SDA output
259
260 i2c_data = send_data;
261 for (i=8 ; i>0 ; i--) {
262 //ビット"1","0"送信
263 if (i2c_data & 0x80) { // ビットセット
264 I2C_SDA = 1;
265 } else {
266 I2C_SDA = 0;
267 }
268 i2c_data = i2c_data << 1; // next bit set
269
270 I2C_SCL = 1; // 1ビット送信
271 NOP();
272 NOP();
273 NOP();
274 NOP();
275 I2C_SCL = 0;
276 }
277 I2C_SDA_TRIS = 1; // SDA input
278
279 return;
280 }
281
282
283 //---from:
284 //I2C_snd_char2()
285 //lcdStr()
286 static unsigned char I2C_ackchk() {
287 //相手デバイスからの肯定応答
288 unsigned char i2c_data;
289
290 I2C_SCL = 1; // ACKビット受信
291 NOP();
292 NOP();
293 I2C_SCL = 0;
294 NOP();
295 NOP();
296 i2c_data = PORTB & 0x02;
297
298 return(i2c_data);
299 /*
300 もとのプログラムでは、SCLをハイにして、SDAを読み、SCLをローにしていたと思いますが、
301 今回使用した小型液晶AQM..において、
302 オシロスコープでこのack信号の様子を見たところ、
303 SCLがローになったタイミングで液晶のほうからack信号が送信されているようでした。
304 そのためそのままだと常にfalseを返すことになっていたと思うので、
305 上記のように変更しました。
306 (ただ、ackはtrueにしろ、falseにしろ、この関数を利用するプログラムのほうで何もしていないので、直しても何も変わりません(o_o;)
307 */
308 }
309
310
311 //---from:
312 //I2C_snd_char2()
313 //main()
314 static void wait_ms(unsigned int ms) {
315 unsigned int c;
316 for (c=ms ; c>0 ; c--) {
317 wait_1ms();
318 }
319 return;
320 }
321
322
323 //***未使用***
324
325 // ==================== I2C Recive ============================
326 static unsigned char I2C_rcv() {
327 unsigned char i2c_data,i;
328
329 I2C_SDA_TRIS = 1; // SDA input
330 for (i=8 ; i>0 ; i--) {
331 NOP();
332 I2C_SCL = 1; // 1ビット受信
333 i2c_data = i2c_data <<1;
334 if (PORTB & 0x02) {
335 i2c_data = i2c_data | 0x01;
336 } else {
337 i2c_data = i2c_data & 0xFE;
338 }
339 I2C_SCL = 0;
340 }
341
342 return(i2c_data);
343 }
344
345
346 // ==================== I2C Recive char ========================
347 static unsigned char I2C_rcv_char(unsigned char ee_p0 ,unsigned char addr1 ,unsigned char addr2) {
348 unsigned char c;
349
350 I2C_start();
351 I2C_send(LCD_ADDR | ee_p0); // スレーブアドレス & Write
352 if (I2C_ackchk()) {
353 // LCD_data('8');
354 }
355 I2C_send(addr1); // 書き込みアドレス1
356 if (I2C_ackchk()) {
357 // LCD_data('9');
358 }
359 I2C_send(addr2); // 書き込みアドレス2
360 if (I2C_ackchk()) {
361 // LCD_data('A');
362 }
363
364 I2C_start();
365 I2C_send(LCD_ADDR | ee_p0 | 0x01); // スレーブアドレス & Read
366 if (I2C_ackchk()) {
367 // LCD_data('B');
368 }
369 c = I2C_rcv();
370 I2C_nacksnd();
371
372 I2C_stop();
373
374 return(c);
375 }
376
377
378 // ==================== I2C ACK send ==========================
379 static void I2C_acksnd() {
380 I2C_SDA = 0; // ACK
381 I2C_SDA_TRIS = 0; // SDA output
382 NOP();
383 I2C_SCL = 1; // ACK送信
384 NOP();
385 NOP();
386 NOP();
387 NOP();
388 I2C_SCL = 0;
389 I2C_SDA_TRIS = 1; // SDA input
390
391 return;
392 }
393
394 // ==================== I2C NACK send =========================
395 static void I2C_nacksnd() {
396 I2C_SDA = 1; // NACK
397 I2C_SDA_TRIS = 0; // SDA output
398 I2C_SCL = 1; // NACK送信
399 NOP();
400 I2C_SCL = 0;
401 NOP();
402 I2C_SDA_TRIS = 1; // SDA input
403
404 return;
405 }
406
407 // ==================== LCD 初期表示 ==========================
408
409 // ==================== LCD 4bit 送信 =========================
410
411 // ==================== LCDコマンドWRITE =================
412
413
414 // ==================== LCDデータWRITE =================
415
416
417 // =============== 1バイトを16進数でLCDに出力 ==========
418
419
420 // ==================== LCDの初期化 ===========================
421
422 // ==================== 50μSウェイトルーチン =================
423 static void wait_50us() {
424 unsigned char i;
425
426 for (i=32 ; i>0 ; i--) {}
427 return;
428 }
429
430 // ==================== 1mSウェイトルーチン =================
431 static void wait_1ms() {
432 unsigned char i;
433
434 for (i=179 ; i>0 ; i--) {
435 NOP();
436 NOP();
437 NOP();
438 }
439 return;
440 }
441
442 // ========================== ここまで ==============================