stm32软件i2c

硬件i2c,,并不是非用不可,,, 硬件i2c需要占用引脚

c 复制代码
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "buzzer.h"
#include "lightSensor.h"
#include "stdio.h"

// 用 PA0 和 PA1 
void my_softI2c_init(){

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitTypeDef GPIO_initStruct = {0};
	
	// 操控引脚 
	GPIO_initStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	
	// 开漏输出
	GPIO_initStruct.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_initStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	// 初始化IO引脚,,
	GPIO_Init(GPIOA,&GPIO_initStruct);
	

}
/**
向 scl 写 0 或者写1
*/
void scl_write(uint8_t level){
	GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)level);
}


void sda_write(uint8_t level){
	GPIO_WriteBit(GPIOA,GPIO_Pin_1,(BitAction)level);
}

uint8_t sda_read(void){
	if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1) == Bit_SET){
		return 1;
	}else{
		return 0;
	}
}

/**

72MHz
*/
void delay_us(uint32_t us){
	
	uint32_t n = us*8;
	for(uint32_t i = 0;i<n;i++);
}

/**
发送起始位
*/
void sendStart(void){
	sda_write(0);
	delay_us(1);
}

/**
发送停止位
*/
void sendStop(void){
	// 确保在 scl为低电平的时候,,去修改 sda
	
	scl_write(0);
	sda_write(0);
	Delay(1);
	
	scl_write(1);
	Delay(1);
	
	sda_write(1);
	Delay(1);
}


uint8_t sendByte(uint8_t byte){
	
	for(int8_t i=0;i<8;i++){
		// 拉低准备数据
		scl_write(0);
		
		if((byte & (0x80 >> i))!=0){
			sda_write(1);
		}else{
			sda_write(0);
		}
		
		delay_us(1);
		scl_write(1);
		delay_us(1);
	}
	
	
	
	scl_write(0);
	// 释放sda线,, 让别人回复
	sda_write(1);
	delay_us(1);
	
	
	scl_write(1);
	delay_us(1);
	// 读取nack 或者ack
	return sda_read();
}



uint8_t receiveByte(uint8_t ackFlag){

	uint8_t byte = 0x00;
	
	for(int8_t i=0;i<8;i++){
		scl_write(0);
		// 释放sda线,, 让别人发数据
		sda_write(1);
		
		delay_us(1);
		scl_write(1);
		delay_us(1);
		// 读取sda
		
		if(sda_read() == 1){
			byte = byte | (0x80 >> i);
		}
		
		
	}
	
	
	// 发送ack
	scl_write(0);
	

	sda_write(ackFlag);
	
	
	delay_us(1);
	scl_write(1);
		
	delay_us(1);
		
	
	return byte;
}



	
	






/**
板载led初始化
*/
void my_onBoardLED_init(){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	GPIO_InitTypeDef GPIO_initStruct = {0};
	
	// 操控引脚 
	GPIO_initStruct.GPIO_Pin = GPIO_Pin_13;
	
	// 板载led ,,是开漏输出
	GPIO_initStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_initStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	// 初始化IO引脚,,
	GPIO_Init(GPIOC,&GPIO_initStruct);
	
	
	GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
}


void my_oled_init(){
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIO_InitTypeDef GPIO_initStruct = {0};
	
	// 操控引脚 
	GPIO_initStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	

	// 必须是开漏,,多设备共用一根线,,如果多个人输出高,,就短路了,,I2C规定只能拉低
	GPIO_initStruct.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_initStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	// 初始化IO引脚,,
	GPIO_Init(GPIOB,&GPIO_initStruct);
	
	
	
	
	
		// 开时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
	
	// 开启复位信号
	RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);
	
	// 关闭复位信号  ,,, 硬件的复位本质上是一个脉冲
	RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);
	
	
	
	I2C_InitTypeDef i2c_initStruct;
	
	i2c_initStruct.I2C_ClockSpeed = 400000;
	
	i2c_initStruct.I2C_Mode = I2C_Mode_I2C;
	
	i2c_initStruct.I2C_DutyCycle = I2C_DutyCycle_2;
	
	I2C_Init(I2C1,&i2c_initStruct);
	
	
	// 闭合I2C1的总开关
	I2C_Cmd(I2C1,ENABLE);

}



/**
接收从机数据
*/
int my_softI2c_receiveBytes(uint8_t addr,uint8_t *pBuffer,uint16_t size){
	sendStart();
	
	if(sendByte(addr | 0x01 ) != 0){
		// 寻址不成功
		sendStop();
		return -1;
	}
	
	
	
	for(uint32_t i=0;i<size;i++){
		
		if(i==size-1){
			pBuffer[i] = receiveByte(0);
		}else{
			pBuffer[i] = receiveByte(1);
		}
		
	
	}
	
	
	sendStop();
	
	
	
	return 0;
	
	

}
/**
addr : 地址
pBuffer: 要发送的数据
size : 要发送数据的数量
*/
int my_softI2c_sendBytes(uint8_t addr,uint8_t *pData,uint16_t size){
	
	sendStart();
	// 写数据,最后一位是0
	if(sendByte(addr & 0xfe ) != 0){
		// 寻址不成功
		sendStop();
		return -1;
	}
	
	for(uint32_t i=0;i<size;i++){
		if(sendByte(pData[i]) != 0){
			// 没有ack,,数据被拒收
				sendStop();
				return -2; 
		}
		
	}
	
	
	
		sendStop();
		return 0;
	
}


int main(void)
{
	

	// 初始化 PA0 和 PA1
	my_softI2c_init();
	

//	uint8_t commands[] = {0x00,0x8d,0x14,0xaf,0xa5};
//	
//	my_softI2c_sendBytes(0x78,commands,5);
//	
	while(1)
	{
		

	}
}
相关推荐
蹊黎8 小时前
Linux 下用 C 语言实现进度条
linux·c语言·单片机
Zw-awa12 小时前
从 CPU 搬运到自动搬运:DMA、空闲中断和两块缓冲
stm32
无敌贵点大王12 小时前
从寄存器层面重学STM32(6)——串口USART实战部分
stm32·单片机·嵌入式硬件
庙堂龙吟奈我何12 小时前
二进制和十六进制
stm32·单片机
国科安芯14 小时前
长期在轨的计算底座:商业空间站与在轨服务飞行器健康管理中的抗辐射MCU—— 面向可维护空间平台的分层容错与安全通信综述
人工智能·单片机·嵌入式硬件·安全·低轨卫星·抗辐射
TST-魚爷14 小时前
小型视频会议室音频踩坑:一体化拾音扩音方案实测分享(易视讯)
stm32·电脑·音视频·钉钉·腾讯会议·zoom会议
不昀16 小时前
RMII切到10Mbps,50MHz参考时钟也要降到5MHz吗?
单片机·嵌入式硬件·硬件设计·以太网接口
路上有只喵17 小时前
认识元器件 · 单片机(MCU/MPU/SOC) · 实战篇6
单片机·嵌入式硬件
国科安芯17 小时前
核电站蒸汽发生器传热管在役无损检测模拟前端的低噪声供电研究
嵌入式硬件·ldo·低压差线性稳压器·无损检测·核电站·蒸汽发生器·传热管
集芯微电科技有限公司18 小时前
40V/24A高频率增强型GaN HEMT功率开关管/高频DC转换/电动工具/GaN充电器 方案首选
人工智能·科技·单片机·嵌入式硬件·深度学习·神经网络·生成对抗网络