硬件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)
{
}
}