FC2ブログ

結構大変だった。。。

PIC16F690はI2Cのマスターモードのシーケンスが書かれてない?
安物マイコンで制御むりだお・・と思ったけどなんとかできたよ

ちなみにブロック図的にこんな回路
ものすごく無理強いさせました
c1
ちなみにMPLAB IDEのHITEC-C v9.80です


安物なんでピン数が少ない。
IOエキスパンダICでI2Cから変換。

マイコンの仕様書見てもI2CのSCLを生成するプリスケーラやクロックジェネレータがなく
直接IOピンを振れさせるのかとおもいきや

実際にそうでしたわw
ただし、SSPレジスタは登録しないといけません


I2C自体0~400kHzで動かせますからね
3.4MHzなるとシーケンスは違ってきますので。
USB2.0とUSB1.1では違う


イニシャライズとしてはこう↓

マイコンのIOピンを定義
SSPレジスタをセット

PCA9554Aのレジスタに
コンフィギュレーションをセットして
IOの入出力を決める

TC1602のLCDのファンクションセット


RS,RW,Eは、LCDにデータを送る前に送ります。
PCA9554Aのターンアラウンドタイムが来た後に、WS,RW,Eをリセットすること
そうでないとLCDに文字が映らない。

少なくともI2Cストップシーケンスを発行してる時にターンアラウンドタイムは
終わるので、次の処理でいいでしょう
※volatile定義されてない変数を間にはさむと動かなくなるかもよ?


これで動くので、作ったコードおいておくよー!

・XTALの定義があるので注意
・TABはデフォルトで4です
lcd_init()で初期化
putsLCD(char *s)=文字列表示。¥n(改行)、¥t(タブ)付き!
printLCD(char *str, ...)=通常のprintf関数みたいな使い方。%d、%s対応!
※まだ開発がいるけどとりあえず出力のみ

LCDはSC1602と共通なので移植できる
ここまでやるのに5日も費やしたなんて・・

開発環境がLiteなせいか浮動小数点は扱えなかった・・・(´・ω・`)

LCDPreDefine.h

#ifndef _LCD_PREDEFINE_
#define _LCD_PREDEFINE_

#include<stdio.h>
#include<string.h>

#define _XTAL_FREQ 16000000

#define RSL RC4
#define RWL RC3
#define EL RC6

#define SCL TRISB6 // I2C bus
#define SDA TRISB4 //
#define SCL_IN RB6 //
#define SDA_IN RB4 //

#define DEVICE_ADDRESS 0b01110010
#define DEVICE_COMMAND_OUTPUT 0b00000001
#define DEVICE_COMMAND_CONFIG 0b00000011

#define ID_INC 0x6
#define ID_DEC 0x4
#define SHIFT_ON 0x5
#define SHIFT_OFF 0x4

#define DISP_ON 0xC
#define DISP_OFF 0x8
#define CURSOR_ON 0xA
#define CURSOR_OFF 0x8
#define BLINK_ON 0x9
#define BLINK_OFF 0x8

#define DISP_SHIFT 0x18
#define CURSOR_MOVE 0x10
#define RIGHT 0x14
#define LEFT 0x10

#define BIT_8 0x30
#define BIT_4 0x20
#define DUTY_16 0x28
#define DUTY_8 0x20
#define FONT_10 0x24
#define FONT_7 0x20

#define TAB_SPACE 4

void lcd_configSet(void);
void lcd_dataSet(void);
void lcd_endSet(void);

void i2c_dly(void);
void i2c_start(void);
void i2c_stop(void);
unsigned char i2c_rx(char ack);
bit i2c_tx(unsigned char d);

void lcd_config(int sel,unsigned char data);
void lcd_init(void);

void locate(int x, int y);
void scroll(int shift,int direction,int num);

int putcharLCD(char data);
int putsLCD(char *s);
int getcharLCD(void); // No program
int getsLCD(void); // No program

int printLCD(const char *str, ...);

#endif



処理が長いので他のヘッダファイルは続きね!
LCD.h↓(作成翌日、小数、unsign対応させました)


#ifndef _LCD_TC1602E13T_
#define _LCD_TC1602E13T_

#include "LCDPreDefine.h"
//Micro :PIC16f690
//LCD :TC1602E-13T
//IO-I2C:PCA9554AN


//SSP format
void i2c_master_init(void){
int i;
SMP=SMP;
CKE=CKE;
DA=0;
RW=1;
UA=0;
CKP=1;
SSPEN=1;
SSPCON|=0b00001011;
SSPIE=0;
SSPIF=0;
}

void i2c_dly(void) { /* I2Cディレイ */
NOP();
}

void lcd_configSet(void){ /* LCDコンフィグセットシーケンス*/
RSL=0;
RWL=0;
NOP();
EL=1;
}

void lcd_endSet(void){ /* LCDリセットシーケンス */
EL=0;
RWL=1;
RSL=1;
}

void lcd_dataSet(void){ /* LCDデータセットシーケンス */
RSL=1;
RWL=0;
NOP();
EL=1;
}

void i2c_start(void){ /* I2C STARTシーケンス出力 */
SDA = 1;
i2c_dly();
SCL = 1;
i2c_dly();
SDA = 0;
i2c_dly();
SCL = 0;
i2c_dly();
}

void i2c_stop(void){ /* I2C STOPシーケンス出力 */
SDA = 0;
i2c_dly();
SCL = 1;
i2c_dly();
SDA = 1;
i2c_dly();
}

unsigned char i2c_rx(char ack){ /* I2C受信 */
char x, d=0;
SDA = 1;
for(x=0; x<8; x++){
d <<= 1;
do {
SCL = 1;
}
while(SCL_IN==0);
i2c_dly();
if(SDA_IN)
d |= 1;
SCL = 0;
}
if(ack) SDA = 0;
else SDA = 1;
SCL = 1;
i2c_dly();
SCL = 0;
SDA = 1;
return d;
}

bit i2c_tx(unsigned char d){ /* I2C送信 */
char x;
static bit b;
for(x=8; x; x--) {
if(d&0x80) SDA = 1;
else SDA = 0;
SCL = 1;
d <<= 1;
SCL = 0;
}
SDA = 1;
SCL = 1;
i2c_dly();
b = SDA_IN;
SCL = 0;
return b;
}

void lcd_config(int command_sel,int cfg_dat_sel,unsigned char data){ /* IOエキスパンダ & LCDコンフィグ設定 */
if(cfg_dat_sel)
lcd_configSet();
else
lcd_dataSet();
i2c_start();
i2c_tx(DEVICE_ADDRESS);
if(command_sel){
i2c_tx(DEVICE_COMMAND_CONFIG);
}else{
i2c_tx(DEVICE_COMMAND_OUTPUT);
}
i2c_tx(data);
i2c_stop();
lcd_endSet();
}

void lcd_i2c_init(void){ /* IOエキスパンダ & LCDイニシャラズ */
SDA = SCL = 1;
SCL_IN = SDA_IN = 0;
__delay_ms(1);
i2c_master_init();
__delay_ms(1);
lcd_config(1,1,0x0);
__delay_ms(15);
lcd_config(0,1,BIT_8|DUTY_16|FONT_7);
__delay_us(100);
lcd_config(0,1,BIT_8|DUTY_16|FONT_7);
lcd_config(0,1,BIT_8|DUTY_16|FONT_7);
lcd_config(0,1,CURSOR_MOVE|RIGHT);
lcd_config(0,1,DISP_ON|CURSOR_OFF|BLINK_OFF);
lcd_config(0,1,ID_INC|SHIFT_OFF);
lcd_config(0,1,0x1);
__delay_ms(1);
}

void locate(int x, int y) /* 液晶のカーソル位置を設定 */
{
lcd_config(0,1,0x80+x+y*0x40);
return ;
}

void scroll(int shift,int direction,int num){ /* ディスプレイの文字をシフト */
if(num>0){
lcd_config(0,1,0x10+shift*0x8+direction*0x4);
scroll(shift,direction,num--);
}else
return ;
}

int putcharLCD(char data){ /* 1文字出力 */
locate(0,0);
lcd_config(0,0,data);
return 1; /* カーソル位置を出力 */
}

int putsLCD(char *s) /* 文字列出力 */
{
int i=0,j=0;
locate(0,0);
do{
if(i==16){
locate(0,1);
i=0; j++;
}
if(j==2){
locate(0,0);
j=0;
}
switch(*s){
case '\0' : break;
case '\n' : locate(0,1);
i=0; j++;
break;
case '\t' : if((i+TAB_SPACE)>=16){
locate(0,1); j++;
i=i-(16-TAB_SPACE);
}else{
i=i+TAB_SPACE;
}
break;
default :
locate(i,j);
lcd_config(0,0,*s);
i++;
break;
}
}while(*s++);
return (j*16+i); /* カーソル位置を出力 */
}

int getcharLCD(void){ /* 現在カーソル位置の1文字を取得 */
/* No program */
}

int getsLCD(void){ /* LCD表示文字を取得 */
/* No program */
}

int printLCD(const char *str, ...){ /* 模擬printf関数 */
va_list set;
char ps[32];
char *buf_s;
double buf_f,seisu,syousu;
int i,j;
int x=0,y=0;

locate(0,0);
va_start(set,str);
while(*str){
if(x==16){
locate(0,1);
x=0; y++;
}
if(y==2){
locate(0,0);
y=0;
}
if(*str=='%'){
*str++;
switch(*str){
case 'i' :
case 'd' :
sprintf((char *)ps,"%d",va_arg(set,int)); //MAX=16bit
i=(int)strlen(ps)+x;
for(x,j=0;x if(x==16){
locate(0,1);
x=0; y++;
}
if(y==2){
locate(0,0);
y=0;
}
locate(x,y);
lcd_config(0,0,(unsigned char)ps[j]);
}
break;
case 'u' :
sprintf((char *)ps,"%u",va_arg(set,unsigned)); //MAX=16bit
i=(int)strlen(ps)+x;
for(x,j=0;x if(x==16){
locate(0,1);
x=0; y++;
}
if(y==2){
locate(0,0);
y=0;
}
locate(x,y);
lcd_config(0,0,(unsigned char)ps[j]);
}
break;
case 'f' :
buf_f=va_arg(set,double);
syousu=modf(buf_f,&seisu);
sprintf((char *)ps,"%d.%d",(int)seisu,abs((int)(syousu*10000.0)));
i=(int)strlen(ps)+x;
for(x,j=0;x if(x==16){
locate(0,1);
x=0; y++;
}
if(y==2){
locate(0,0);
y=0;
}
locate(x,y);
lcd_config(0,0,(unsigned char)ps[j]);
}
break;
case 'c' :
locate(x,y);
lcd_config(0,0,(unsigned char)va_arg(set,char));
x++;
break;
case 's' :
buf_s=va_arg(set,char *);
do{
if(*buf_s=='\0') break;
if(x==16){
locate(0,1);
x=0; y++;
}
if(y==2){
locate(0,0);
y=0;
}
locate(x,y);
lcd_config(0,0,(unsigned char)*buf_s);
x++;
}while(*buf_s++);
break;
default : break;
}
}else{
switch(*str){
case '\0' : break;
case '\n' : locate(0,1);
x=0; y++;
break;
case '\t' : if((x+TAB_SPACE)>=16){
locate(0,1); y++;
x=x-(16-TAB_SPACE);
}else{
x=x+TAB_SPACE;
}
break;
default :
locate(x,y);
lcd_config(0,0,(unsigned char)*str);
x++;
break;
}
}
*str++;
}
va_end(set);
return (y*16+x);
}
スポンサーサイト



テーマ : 趣味と日記
ジャンル : 趣味・実用

コメントの投稿

非公開コメント

ぶろぐかんりしゃ

SmartWoods
最近MoEは・・・
一休み

***** ひとこと *****

MoEの後継ともいわれる
Resonance gamez
完全スキルMMOが
気になるところ



********************


↓2016/3/26更新
My MoE









**********

NEWとらっくばっく
あーかいぶ
かてごりー
リンク
ぶろぐないけんさく
RSSふぃーど
おともだちになろ

この人とブロともになる