两块stm32f407开发板进行模拟iic通信,想实现主机接收从机的数据,但现在主机可以发地址,但从机无法正常发送数据,目前已经成功了的是主机发送iic报文,从机可以正常进入中断实现判定,找不到从机无法发送数据的原因
主机配置代码
#include "myiic.h"
#include "delay.h"
#include "stm32f4xx_i2c.h"
#include "bsp_led.h"
#include "bsp_relay.h"
//初始化IIC
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
IIC_SCL=1;
IIC_SDA=1;
GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x03; //从机地址,一定要设置正确
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;//事件中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;//错误中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE);
I2C_Cmd(I2C1, ENABLE);
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
发送主函数
while(1){
IIC_Start();//IIC开始信号
IIC_Send_Byte(0x10);//发送从机地址,假设从机地址为0
IIC_Wait_Ack();//等待应答
IIC_Read_Byte(0);//给从机发送数据,从机收到数据后打开继电器和指示灯
IIC_Stop();//IIC停止发送
delay_ms(1);
}
从机接收配置
#include "myiic.h"
#include "delay.h"
#include "stm32f4xx_i2c.h"
#include "led.h"
#include "bsp_relay.h"
/*---------IIC1---------------*/
uint8_t Buffer_Rx_IIC1[40];//接收缓存
uint8_t Rx_Idx_IIC1=0;//接收计数
uint8_t Flag_RcvOK_IIC1 = 0;// 接收完成标志
uint8_t Tx_Idx_IIC1=0;//发送计数
u8 Response_Message[40];//发送缓存
u8 I2C1_ADDRESS;//7 位 I2C 地址
//初始化IIC
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
IIC_SCL=1;
IIC_SDA=1;
GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x10; //从机地址,一定要设置正确
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;//事件中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;//错误中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE);
I2C_Cmd(I2C1, ENABLE);
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
void I2C1_EV_IRQHandler(void)
{
__IO uint32_t SR1Register =0;
__IO uint32_t SR2Register =0;
SR1Register = I2C1->SR1;
SR2Register = I2C1->SR2;
/* I2C1是从机(MSL = 0) */
if((SR2Register &0x0001) != 0x0001)
{
/* 主机已发送地址,地址为被置位·(ADDR = 1: EV1(包括发送和接收)) */
if((SR1Register & 0x0002) == 0x0002)
{
/* 清除标志位 */
SR1Register = 0;
SR2Register = 0;
Rx_Idx_IIC1=0;
Tx_Idx_IIC1=0;
}
/* 接收数据(RXNE = 1: EV2) */
if((SR1Register & 0x0040) == 0x0040)
{
Buffer_Rx_IIC1[Rx_Idx_IIC1++] = I2C1->DR;
SR1Register = 0;
SR2Register = 0;
// if(Buffer_Rx_IIC1[0] == 0x10)
// {
// GPIO_ResetBits(C1_PORT, C1_PIN);
// GPIO_SetBits(L1_PORT, L1_PIN);
// }
}
/* 检测到停止条件(STOPF =1: EV4) */
if(( SR1Register & 0x0010) == 0x0010)
{
I2C1->CR1 |= 0x0001;
SR1Register = 0;
SR2Register = 0;
Flag_RcvOK_IIC1 = 1;
}
/* 发送数据(TxE = 1: EV3、EV3-1) */
if((SR1Register & 0x0080) == 0x0080)
{
I2C1->DR = Buffer_Rx_IIC1[0];
SR1Register = 0;
SR2Register = 0;
I2C_SendData(I2C1,0x10);
}
/* 检测到非应答(AF =1: EV3-2) */
if(( SR1Register & 0x0400) == 0x0400)
{
I2C1->SR1 &= 0xFDFF;
SR1Register = 0;
SR2Register = 0;
}
}
}
void I2C1_ER_IRQHandler(void)
{
__IO uint32_t SR1Register =0;
__IO uint32_t SR2Register =0;
SR1Register = I2C1->SR1;
SR2Register = I2C1->SR2;
if(I2C_GetITStatus(I2C1,I2C_IT_SMBALERT)) {
}
else if(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT)) {
}
else if(I2C_GetITStatus(I2C1, I2C_IT_PECERR)) {
}
else if(I2C_GetITStatus(I2C1, I2C_IT_OVR)) {
}
else if(I2C_GetITStatus(I2C1, I2C_IT_AF)) {
I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
}
else if(I2C_GetITStatus(I2C1, I2C_IT_ARLO)) {
}
else if(I2C_GetITStatus(I2C1, I2C_IT_BERR)) {
}
I2C1->CR1 |= 0x0001;
SR1Register = 0;
SR2Register = 0;
}
void control(void)
{
if(Buffer_Rx_IIC1[0] == 0x01)
{
ch1_ON;
GPIO_ResetBits(C1_PORT, C1_PIN);
GPIO_SetBits(L1_PORT, L1_PIN);
IIC_Send_Byte(0x10);
}
}
void check_address(void)
{
delay_ms(300);
if(relay_A0_READ == 1 || relay_A1_READ == 0) // " 0 1 "
{
if(relay_A2_READ == 0 || relay_A3_READ == 0)
{
I2C1_ADDRESS = 0X01;
}
else if(relay_A2_READ == 1 || relay_A3_READ == 0)
{
I2C1_ADDRESS = 0X05;
}
else if(relay_A2_READ == 0 || relay_A3_READ == 1)
{
I2C1_ADDRESS = 0X09;
}
}
if(relay_A0_READ == 0 || relay_A1_READ == 1) // " 1 0 "
{
if(relay_A2_READ == 0 || relay_A3_READ == 0)
{
I2C1_ADDRESS = 0X02;
}
else if(relay_A2_READ == 1 || relay_A3_READ == 0)
{
I2C1_ADDRESS = 0X06;
}
else if(relay_A2_READ == 0 || relay_A3_READ == 1)
{
I2C1_ADDRESS = 0X0A;
}
}
if(relay_A0_READ == 1 || relay_A1_READ == 1) // " 0 0 "
{
if(relay_A2_READ == 0 || relay_A3_READ == 0)
{
I2C1_ADDRESS = 0X03;
}
else if(relay_A2_READ == 1 || relay_A3_READ == 0)
{
I2C1_ADDRESS = 0X07;
}
else if(relay_A2_READ == 0 || relay_A3_READ == 1)
{
I2C1_ADDRESS = 0X0B;
}
}
if(relay_A0_READ == 0 || relay_A1_READ == 0) // " 1 1 "
{
if(relay_A2_READ == 1 || relay_A3_READ == 0)
{
I2C1_ADDRESS = 0X04;
}
else if(relay_A2_READ == 0 || relay_A3_READ == 1)
{
I2C1_ADDRESS = 0X08;
}
else if(relay_A2_READ == 1 || relay_A3_READ == 1)
{
I2C1_ADDRESS = 0X0C;
}
}
}
这是目前在示波器上显示的主机接收从机数据的时序图
程序很奇怪呢,既然是IO模拟,为什么又启用了硬件I2C?是不是模拟的时序和硬件的时序产生了冲突
搞个逻辑分析仪来进行调试吧,示波器深度不够,不太好调,从机IIC确实得使用中断,会使用HAL库么,这里有篇博客写得还不错,你可以按照这个方式先跑一跑,看一下波形正不正常。若是跑得通,回头一步步调试自己的工程,可能是你主机模拟的时序不是很好,具体你要结合你的通信波形进行分析。
https://blog.csdn.net/qq_36561846/article/details/117474070
接收
/*接收应答信号,若接收到非应答信号,则发送停止信号(SDA低电平表示应答,高电平表示非应答)*/
unsigned char IIC_Soft::IIC_ReceiveACK()
{
unsigned char state;
IIC_DataDir(DIRECTION_IN); //SDA为输入模式
SET_SDA; //释放SDA
SET_SCL;
state = READ_SDA;
RESET_SCL;
if(state) //若接收到非应答信号,发送停止信号
{
IIC_Stop();
}
return state;
}