Skip to content

Instantly share code, notes, and snippets.

@qdk0901
Last active January 15, 2019 20:25
Show Gist options
  • Save qdk0901/2526ab39a2d7acff8bdf543b2c8c1bb9 to your computer and use it in GitHub Desktop.
Save qdk0901/2526ab39a2d7acff8bdf543b2c8c1bb9 to your computer and use it in GitHub Desktop.
i2c slave with PMS150C
#define I2C_SLAVE_ADDRESS (0xA0 >> 1)
#define BUF_SIZE 16
enum {
IDLE,
START,
STOP,
ADDR,
OP,
READDATA,
WRITEDATA,
IACK1,
IACK2,
WACK1,
WACK2,
RACK
};
enum {
LOW,
HIGH
};
enum {
INPUT,
OUTPUT
};
sda equ PA.4;
scl equ PA.3;
sdac equ PAC.4;
sclc equ PAC.3;
BYTE last, current;
BYTE sda_change, scl_change;
BYTE state;
BYTE data;
BYTE len;
BYTE buf[BUF_SIZE];
WORD ptr;
BYTE wrt;
BYTE pause_sda;
void clear_sda()
{
pause_sda = 1;
sdac = OUTPUT;
sda = LOW;
}
void release_sda()
{
pause_sda = 0;
sdac = INPUT;
sda = HIGH;
}
void sda_low()
{
pause_sda = 1;
sdac = OUTPUT;
sda = LOW;
}
void sda_high()
{
pause_sda = 1;
sdac = INPUT;
sda = HIGH;
}
void check_scl()
{
if (scl == HIGH) {
switch(state) {
case ADDR:
if (sda)
data = (data << 1) | 1;
else
data = (data << 1);
len++;
if (len < 7)
break;
if (data != I2C_SLAVE_ADDRESS)
state = IDLE;
else
state = OP;
break;
case OP:
//读完7位地址位,剩1位读写位
if (sda)
data = 1;
else
data = 0;
state = IACK1;
break;
case IACK1:
state = IACK2;
break;
case WRITEDATA:
if (sda)
data = (data << 1) | 1;
else
data = (data << 1);
len++;
if (len < 8)
break;
len = 0;
*ptr = data;
ptr++;
data = 0;
state = WACK1;
break;
case WACK1:
state = WACK2;
break;
case READDATA:
if (len < 8)
break;
ptr++;
data = *ptr;
len = 0;
state = RACK;
break;
case RACK:
if (sda == HIGH)
state = IDLE;
else
state = READDATA;
break;
default:
break;
}
} else {
switch(state) {
case IACK1:
clear_sda();
break;
case IACK2:
release_sda();
if (data == 0) {
len = 0;
ptr = buf;
state = WRITEDATA;
wrt = 1;
} else {
state = READDATA;
wrt = 0;
ptr = buf; ptr++; //指向data0
len = 1;
//make sda high/low
data = *ptr;
if (data.7) {
sda_high();
} else {
sda_low();
}
data <<= 1;
}
break;
case WACK1:
clear_sda();
break;
case WACK2:
release_sda();
state = WRITEDATA;
break;
case READDATA:
//make sda high low
if (data.7) {
sda_high();
} else {
sda_low();
}
data <<= 1;
len++;
break;
case RACK:
release_sda();
break;
default:
break;
}
}
}
void check_sda()
{
//pms150c主动操作sda的时候,不检查sda是否跳变
if (pause_sda)
return;
if (scl == HIGH && !scl_change) {
if (sda == HIGH) {
//scl高电平,sda跳成高电平,是STOP信号
state = IDLE;
if (wrt) {
//write done
} else {
//read done
}
len = 0;
ptr = buf;
data = 0;
} else {
//scl高电平,sda跳成高电平,是START信号
//状态机转成准备接收地址的状态
state = ADDR;
len = 0;
ptr = buf;
data = 0;
}
}
}
void i2c_init()
{
//设置所有pin为输入
PAC = 0;
//sda scl加上弱上拉
PAPH = _FIELD(sda, scl);
state = IDLE;
data = 0;
len = 0;
ptr = buf;
pause_sda = 0;
current = PA;
last = current;
}
void FPPA0 (void)
{
.ADJUST_IC SYSCLK=IHRC/2, IHRC=16MHz, VDD=5V;
// WatchDog Disable, RAM 0 ~ 0xF temporary be used
// You can add the follow code :
// CLKMD.En_WatchDog = 1; // WatchDog Enable
i2c_init();
while (1)
{
//读取
current = PA;
sda_change = (last ^ current) & _FIELD(sda);
scl_change = (last ^ current) & _FIELD(scl);
last = current;
if (scl_change)
check_scl();
if (sda_change)
check_sda();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment