📄 pic主机模拟i2c读从机.txt
字号:
通讯协议:
引脚定义:slave_I2C_data 接到PIN_B1;
slave_I2C_clk接到PIN_B2;
1接收起始位: 当我收到PIN_B1从1变为0时,我会立即进入INT1中断服务程序;这时,PIN_B2必须为1,否则,会立即退出INT1中断服务程序.也就是说,IIC的起动条件必须满足:在PIN_B2=1时,PIN_B1脚出现一个下降沿;若条件满足,程序接收状态;
2 等待PIN_B2再次变1,发0XAA给我,不带开始位;
#define SCLK PIN_B2
#define DATA PIN_B1
//主机发送"启动条件"函数;
void I2CStart(void)
{
//屏蔽所有中断
output_high(DATA);
output_high(SCLK); //将DATA脚和SCLK置为高电平,为发送启动条件做准备
delay_us(4);
output_low(DATA); //在SCLK为高电平期间,DATA脚出现下降沿,表示"起动I2C"
delay_us(4);
output_low(SCLK); //SCLK脚置低电平,为下次移位做准备;
}
//主机发送"停止条件"函数;
void I2CStop(void)
{
output_low(SCLK);
output_low(DATA); //将DATA脚和SCLK置为低电平,为发送"停止条件"做准备
delay_us(4);
output_high(SCLK);
delay_us(4);
output_high(DATA); //在SCLK为高电平期间,DATA脚出现上降沿,表示"停止I2C"
//开所有中断允许位
}
//从I2C输出一个字节
void write_I2C_byte(BYTE cmd) {
BYTE i;
for(i=0;i<=7;++i) {
output_bit(DATA, shift_left(&cmd,1,0) ); //将cmd所指的单元左移一位,右端补0,移出的位经DATA脚输出
//先送出cmd所指单元的最高位
output_high(SCLK); //SCLK脚上升沿到来时,PCF8563收到一位值;
output_low(SCLK); //SCLK脚置低电平,为下次移位做准备;
}
}
//从I2C读入一个字节
BYTE read_I2C_byte( ) {
BYTE i,data;
for(i=0;i<=7;++i) {
shift_left(&data,1,input(DATA)); //CPU从PCF8563读入1位,先读入的是发送数据的最高位;
output_high(SCLK); //SCLK脚上升沿到来时,告诉PCF8563已经移出一位值;
delay_us(2);
output_low(SCLK); //SCLK脚置低电平,为PCF8563下次移位做准备
delay_us(2);
}
return(data);
}
/**-----------------------------------------------------------------------------
函数说明:I2C专用,等待从器件接收方的应答
---------------------------------------------------------------------------------*/
int1 WaitAck(void)
{
int errtime=255;//因故障接收方无ACK,超时值为255.
//output_float(DATA); //将DATA引脚设为输入,开集电极连接
output_high(DATA);
delay_us(2);
output_high(SCLK); //SCLK脚上升沿到来时,PCF8563发送ACK信号;
delay_us(2);
//bit_set(*0xF94,4); //端口C的方向寄存器地址为0xF94
//将端口C的方向寄存器的第4位,置1,即将PIN_C4设置为输入方式
while(input(DATA)){
errtime--;
if (!errtime)
{I2CStop();
//bit_clear(*0xF94,4); //端口C的方向寄存器地址为0xF94,DATA脚设置为输出
//SystemError=0x11;
return FALSE;
}
}
output_low(SCLK);
return TRUE;
}
/**-------------------------------------------------------------------------------
函数说明:I2C专用,主器件为接收方,从器件为发送方时,应答信号。
---------------------------------------------------------------------------------*/
void SendAck(void)
{
output_low(DATA); //将DATA脚设置为低电平,该位值是即发出的"应答信号";
delay_us(2);
output_high(SCLK); //SCLK脚上升沿到来时,PCF8563收到一位值;
delay_us(2);
output_low(SCLK); //SCLK脚置低电平,一个移位时钟结束;
}
/**-------------------------------------------------------------------------------
函数说明:I2C专用,主器件为接收方,从器件为发送方时,非应答信号。
}**-------------------------------------------------------------------------------*/
void SendNotAck(void)
{
output_high(DATA); //将DATA脚设置为高电平,该位值是即发出的"非应答信号";
delay_us(2);
output_high(SCLK);//SCLK脚上升沿到来时,PCF8563收到一位值;
delay_us(2);
output_low(SCLK); //SCLK脚置低电平,一个移位时钟结束;
}
//主机发送函数
void write_IIc(int *buff)
{int i;
2CStart(); //发开始条件
write_I2C_byte(0xAA); //发送"写器件地址","写器件地址"为0xAA
WaitAck(); //等待主机P_B1脚被从机PIN_B1拉低,等待从机应答;
for(i=0;i<5;i++)
{write_I2C_byte(buff[i]); //发送器件的data值(ASCII格式)
buff++;
//if(i<4) WaitAck(); //主机等待P_B1脚被从机PIN_B1拉低,发应答信号;
//因为从机不接收应答,所以主机不用发应答
}
I2CStop();
}
下面是从机接收程序:
int1 wait_I2C_clk_high(){
int sys_couter=255;
while( !input(slave_I2C_clk))
{
sys_couter--;
if(sys_couter==0)
{
//enable_interrupts(INT_EXT1);//使能外部中断1
return FALSE;//超时;
}
}
return TRUE;
}
//从IIC读入一个字节
BYTE read_IIC_byte( ) {
BYTE i=8,data;
do{
shift_left(&data,1,input(slave_I2C_data)); //slave从从主机发送器读入1位,先读入的是发送数据的最高位;
i--;
if(i!=0){
if( !wait_I2C_clk_high() ) return(0x00);//超时,返回0;
}
}while(i!=0);
return(data);
}
//当从机PIN_B1脚出现下降沿时,进入面中断服务程序
#INT_EXT1
void ext_int1_service()
{
BYTE j,SLAVE_address;
int1 receive_ok;
char receive_temp[6]; //声明暂时用来存放接收到的数据,以ASCII格式存放
if( input(slave_I2C_clk)) //判断是否为开始条件,若是,则执行下面,进入I2C通讯;若不是,则退出
{disable_interrupts(INT_EXT1);//不使能外部中断1
if( wait_I2C_clk_high() ) //等待PIN_B2再次变高,若超时,则退出I2C接收;若没有超时,则接收"器件地址0XAA"
{SLAVE_address=read_IIC_byte(); //读到一个字节;
if(SLAVE_address==0xaa) //若地址相符合,则执行下面语句;否则,退出I2C接收
{
if( wait_I2C_clk_high() ) //等待PIN_B2再次变高,若超时,则退出I2C接收;若没有超时,则本从机发送应答ACK
{output_low(slave_I2C_data);//本从机发送应答ACK;
if( wait_I2C_clk_high() ) //等待PIN_B2再次变高,若超时,则退出I2C接收;
{for(j=0;j<=4;j++)
{receive_temp[j]=read_IIC_byte();//每读到一个字节,不发应答;
if(receive_temp[j]!=0) receive_ok=1;
else{
receive_ok=0;
break;
}
}
if(receive_ok)
{strcpy( receive_string_buffer,receive_temp );//将receive_temp所指内容拷贝到receive_string_buffer中;
write_string_to_DAC7612U(receive_string_buffer,14); //将接收到的5位ASCII码写入DAC7612U
lcd1604_display(receive_string_buffer); //将接收到的5位ASCII码写入LCD显示;
}
}
}
}
}
enable_interrupts(INT_EXT1);//使能外部中断1
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -