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)
	{
		

	}
}
相关推荐
殷忆枫1 小时前
基于STM32和LD3320语音模块串口交互
stm32·单片机·嵌入式硬件
知识噬元兽1 小时前
【工具使用】STM32CubeMX-QSPI配置-实现NorFlash读写
stm32·单片机·嵌入式硬件
知识噬元兽1 小时前
【工具使用】STM32CubeMX-FATFS文件系统
stm32·单片机·嵌入式硬件
广州灵眸科技有限公司10 小时前
瑞芯微(EASY EAI)RV1126B 核心板供电电路
linux·运维·服务器·单片机·嵌入式硬件·电脑
浩浩测试一下11 小时前
汇编 16位32位64位通用寄存器(逆向分析)
汇编·windows·stm32·单片机·嵌入式硬件·逆向·二进制
潜创微科技13 小时前
IT68353:双 DP1.4a+HDMI2.0 转 HDMI2.0 单芯片 KVM 切换方案
嵌入式硬件·音视频
踏着七彩祥云的小丑13 小时前
嵌入式测试学习第 17 天:常见接口:USB、Type-C、排针
单片机·嵌入式硬件
szxinmai主板定制专家14 小时前
电力设备RK3568/RK3576+FPGA,多系统混合部署Linux+RTOS RT-THREAD,强实时性
linux·运维·服务器·人工智能·嵌入式硬件·fpga开发
振南的单片机世界16 小时前
EXTI边沿触发:按键一按就通知CPU,不用轮询
stm32·单片机·嵌入式硬件