Although hardware I2C is efficient, I always encounter various problems when debugging. I don’t have much time to mess around with it due to the rush of the project, so I use simulated I2C to complete it. Although the efficiency is not very good, it is simple and fast...
Without further ado, here is a fully annotated version of the simulated I2C code, which is applicable to the STM32 series. For other microcontrollers, you need to modify the definitions of SCL and SDA and modify the delay function.
#include "stm32f10x.h"
#define HIGH 1
#define LOW 0
#define TRUE 1
#define FALSE
/* Here we use the STM32F103RC chip, using PB6 and PB7 as SCL and SDA respectively.
Other chips use appropriate GPIO ports according to needs */
#define SDA_IN() {GPIOB->CRL& = 0X0FFFFFFF; GPIOB->CRL |= 4<<28;}
#define SDA_OUT() {GPIOB->CRL& = 0X0FFFFFFF; GPIOB->CRL |= 3<<28;}
#define IIC_SCL PBout(6) //SCL
#define IIC_SDA PBout(7) //SDA
#define READ_SDA PBin(7) // Input SDA
void delay_us(u16 time)
{
u16 i = 0;
while(time--)
{
i = 10; //A random value, meaningless, just consuming CPU time, the compiler may be optimized
while(i--);
}
}
/* Initialize I2C */
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_Init_Structure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_Init_Structure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init_Structure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_Init_Structure);
GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);
}
/* Generate I2C start signal */
void IIC_Start(void)
{
/* Set the SDA line to output */
SDA_OUT();
/* Before starting to transmit data, pull both SDA and SCL high */
IIC_SDA = HIGH;
IIC_SCL = HIGH;
delay_us(5);
/* According to the I2C bus definition: When SCL is high, the data jumps from high to low to indicate the start signal */
IIC_SDA = LOW;
delay_us(5);
/*
When SCL is low, no data is transmitted and it is not used as a start or end condition.
So we can start sending data without causing a start or end signal
This is called clamping the I2C bus.
*/
IIC_SCL = LOW;
}
/* Generate I2C stop signal */
void IIC_Stop(void)
{
SDA_OUT(); //sda line output
/*
First pull SCL low so that SDA can be switched to a low state without causing repeated start signals.
Remember the previous comment on I2C Start? When SCL is high, SDA changes from high to low.
*/
IIC_SCL = LOW;
/*
SCL has been pulled low before, so here we can pull SDA low without restraint.
Prepare for the end signal
*/
IIC_SDA = LOW;
delay_us(5);
/* Okay, let's start generating the end signal: First, we need to pull SCL high (why? Because the I2C bus specifies
Only when SCL is high is it the effective time to transmit data or generate start/end signals) */
IIC_SCL = HIGH;
/* Okay, we have already pulled SDA low, so here we just need to set SDA high to complete it */
IIC_SDA = HIGH;
delay_us(5);
}
/*
Meaning of the response signal:
The Master needs to wait for the Slave's ACK after sending each 8 bits of data.
That is, at the 9th clock, if the slave IC sends an ACK, then SDA will be pulled low.
If there is no ACK, SDA will be set high, which will cause the Master to issue a Restart or Stop process
*/
/*
Waiting for the response signal to arrive
*/
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime = 0;
IIC_SDA = HIGH;
delay_us(5);
/* Set SDA to input mode, so as to read the ACK on SDA */
SDA_IN();
/* Set SCL high to perform a read operation */
IIC_SCL = HIGH;
delay_us(5);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime > 250)
{//No ACK received from IC within the specified time, timeout processing
return FALSE;
}
}
/*
OK, this means there is no timeout and SDA is read as low, indicating that ACK confirmation is received
Then you can go home and set SCL to low level (why? Because effective operations are all in
Only when SCL is high)
*/
IIC_SCL = LOW;
return TRUE;
}
/*
Send ACK confirmation operation
The purpose of issuing this operation is to let the slave IC know that we have received the data.
In this way, the IC will not perform the Restart or Stop process.
*/
void IIC_Ack(void)
{
/* The first step is to pull SCL low first to avoid SDA changes affecting I2C */
IIC_SCL = LOW;
/* Then we set SDA to output mode and prepare to output data */
SDA_OUT();
/* Pull SDA low, so that the confirmation signal is put on the bus, only the clock signal is missing */
IIC_SDA = LOW;
delay_us(5);
/* Pull SCL high to generate the necessary valid operation clock signal */
IIC_SCL = HIGH;
delay_us(5);
/*
There has been a delay before, and the clock is almost up, so the ACK signal ends
You can't keep occupying the bus all the time */
IIC_SCL = LOW;
}
/*
For NACK, the I2C bus is defined as follows:
When the SDA line remains high during the 9th clock pulse, it is defined as NACK.
The master either generates a Stop condition to abandon the transmission or repeats the Start condition to
Initiate a new beginning
*/
void IIC_NAck(void)
{
IIC_SCL = LOW;
SDA_OUT();
/* According to the definition, pull SDA high as the definition of NACK */
IIC_SDA = HIGH;
delay_us(5);
/* Set to high level, send NACK signal */
IIC_SCL = HIGH;
delay_us(5);
/* Pull SCL low, sending completed */
IIC_SCL = LOW;
}
void IIC_Send_Byte(u8 txd)
{
u8 t;
/* Now that data transmission has started, switch the SDA port to output mode first */
SDA_OUT();
/* Pull the clock signal low, prepare the data and then pull it high for transmission */
IIC_SCL = LOW;
for(t = 0; t < 8; t++)
{
/* I2C data is transmitted in big-endian format, i.e. the high bit is transmitted first */
if((txd&0x80) >> 7)
IIC_SDA = HIGH;
else
IIC_SDA = LOW;
txd <<= 1;
/* It is necessary to make a delay */
delay_us(5);
/* Pull SCL high to transmit data */
IIC_SCL = HIGH;
delay_us(5);
/* Pull SCL low, transmission completed */
IIC_SCL = LOW;
delay_us(5);
}
}
u8 IIC_Read_Byte(void)
{
unsigned char i, receive = 0;
/* Switch the SDA port to input mode, ready to read data */
SDA_IN();
for(i = 0; i < 8; i++ )
{
/* Pull SCL low */
IIC_SCL = LOW;
delay_us(5);
/* Pull SCL high again to generate a valid clock signal */
IIC_SCL = HIGH;
/* Read data on the bus */
receive = (receive << 1) | READ_SDA;
delay_us(5);
}
return receive;
}
Previous article:Detailed explanation of STM32 startup assembler
Next article:GPIO port simulates I2C
Recommended ReadingLatest update time:2024-11-16 14:49
- Popular Resources
- Popular amplifiers
- The STM32 MCU drives the BMP280 absolute pressure sensor program and has been debugged
- DigiKey \"Smart Manufacturing, Non-stop Happiness\" Creative Competition - Small Weather Station - STM32F103 Sensor Driver Code
- LwIP application development practical guide: based on STM32
- CMOS analog integrated circuit design and simulation examples
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Help with AD18 pin display problem!!
- How to choose the right Cortex-based MCU application design
- C8051F340 Development Board
- "【TGF4042 Signal Generator】" Circuit Parameter Measurement
- EEWORLD University - Texas Instruments Deep Learning (TIDL) Overview
- Can the transmission speed of Zigbee be achieved on a small car?
- Applying Over-the-Air Firmware Upgrades to MSP 430 Microcontrollers
- LED glass screen
- Download and get a gift! Meet spring and have fun with us! Come and learn about optical communication test and measurement solutions with Keysight
- Best Practices for 4G/5G Smartphones: How to Achieve Aperture Tuning? (Part 2)