Author:家有仙妻谢掌柜
Date:2021/2/18
今年会更新一个系列,小四轴无人机从功能设计→思维导图→原理图设计→PCBLayout→焊接PCB→程序代码的编写→整机调试一系列,以此记录自己的成长历程!
这个小四轴无人机是大学时期学习制作的,加上现在工作学习对嵌入式的理解更加深入,因此想要重新梳理一下小四轴,之后在此基础上实现大四轴的飞控设计,这些都将在工作之余完成!
//小四轴无人机设计MCU与MPU6500进行通信,用到I2C
#include "i2c.h"
volatile uint32_t _time_out = LONG_TIMEOUT;
/*******************************************************************************
* fuction i2c_init
* brief i2c配置初始化
* param 无
* return 无
*******************************************************************************/
void i2c_init(void)
{
/*结构体变量定义*/
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
/*开启引脚时钟*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF, ENABLE); //开的是IO口的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);//开的是I2C的时钟
/*开启引脚复用功能PA9/PA10*/
GPIO_PinAFConfig(GPIOF, GPIO_PinSource6, GPIO_AF_4);
GPIO_PinAFConfig(GPIOF, GPIO_PinSource7, GPIO_AF_4);
/*引脚的配置PA9/PA10*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOF,&GPIO_InitStructure);
/*I2C的配置*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //I2C 模式
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_InitStructure.I2C_DigitalFilter = 0x00;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_Timing = SENSOR_I2C_TIMING; //宏定义 0x00200404
I2C_Init(I2C2,&I2C_InitStructure);
I2C_Cmd(I2C2, ENABLE);
}
/*******************************************************************************
* fuction i2c_timeout_callback
* brief I2C通信超时复位函数
* param 无
* return 超时标志 // 成功 失败 超时 做一个枚举
*******************************************************************************/
I2C_StatusTypDef i2c_timeout_callback(void)
{
I2C2->CR1|=I2C_CR1_SWRST; // I2C复位
return I2C_TIMEOUT;
}
/*******************************************************************************
* fuction i2c_reg_write
* brief 从主机寄存器写一个字节数据
* param 从机地址 寄存器地址 数据
* return 成功或失败 // 成功 失败 超时 做一个枚举
*******************************************************************************/
I2C_StatusTypDef i2c_reg_write(uint8_t Device_address,uint8_t reg_address,uint8_t data)
{
_time_out = LONG_TIMEOUT;
/* 测试I2C是否空闲 */
/* 不等于RESET就是说明还在忙 */
while(I2C_GetFlagStatus(I2C2,I2C_ISR_BUSY)!= RESET)// 标志位
{
if((_time_out--) == 0)
{
return i2c_timeout_callback();
}
}
/* I2C处于空闲状态。则开始I2C通讯进行相关配置 写设备地址 */
I2C_TransferHandling(I2C2,Device_address,1,I2C_Reload_Mode,I2C_Generate_Start_Write) ; // 调用写的库函数
/* 等待完成*/
_time_out = LONG_TIMEOUT;
while(I2C_GetFlagStatus(I2C2,I2C_ISR_TXIS)== RESET)// 标志位
{
if((_time_out--) == 0)
{
return i2c_timeout_callback();
}
}
/* I2C处于空闲状态。则开始I2C通讯进行相关配置 写设备寄存器地址 */
I2C_SendData(I2C2,reg_address);
/* 等待发送完成*/
_time_out = LONG_TIMEOUT;
while(I2C_GetFlagStatus(I2C2,I2C_ISR_TCR)== RESET)// 标志位
{
if((_time_out--) == 0)
{
return i2c_timeout_callback();
}
}
/* I2C处于空闲状态。则开始I2C通讯进行相关配置 写设备寄存器数据 */
I2C_TransferHandling(I2C2,Device_address,1,I2C_AutoEnd_Mode,I2C_No_StartStop);
/* 发送要写的数据 */
I2C_SendData(I2C2,data);
/* 等待停止标志位完成*/
_time_out = LONG_TIMEOUT;
while(I2C_GetFlagStatus(I2C2,I2C_ISR_STOPF)== RESET)// 标志位
{
if((_time_out--) == 0)
{
return i2c_timeout_callback();
}
}
/* 清除停止标志位*/
I2C_ClearFlag(I2C2,I2C_ICR_STOPCF);
return I2C_OK;
}
/*******************************************************************************
* fuction i2c_read
* brief 从从机寄存器读取一个字节数据
* param 从机地址 寄存器地址 数据长度 数据存放缓存区
* return 成功或失败 // 成功 失败 超时 做一个枚举
*******************************************************************************/
I2C_StatusTypDef i2c_read(uint8_t Device_address,uint8_t reg_address,uint8_t Len,uint8_t *buff)
{
uint8_t Data_Num = 0;
_time_out = LONG_TIMEOUT;
/* 测试I2C是否空闲 */
while(I2C_GetFlagStatus(I2C2,I2C_ISR_BUSY)!= RESET)// 标志位
{
if((_time_out--) == 0)
{
return i2c_timeout_callback();
}
}
/* I2C处于空闲状态。则开始I2C通讯进行相关配置 写设备地址 */
I2C_TransferHandling(I2C2,Device_address,1,I2C_SoftEnd_Mode,I2C_Generate_Start_Write) ; // 调用写的库函数
/* 等待完成*/
_time_out = LONG_TIMEOUT;
while(I2C_GetFlagStatus(I2C2,I2C_ISR_TXIS)== RESET)// 标志位
{
if((_time_out--) == 0)
{
return i2c_timeout_callback();
}
}
/* I2C处于空闲状态。则开始I2C通讯进行相关配置 写设备寄存器地址 */
I2C_SendData(I2C2,reg_address);
/* 等待发送完成*/
_time_out = LONG_TIMEOUT;
while(I2C_GetFlagStatus(I2C2,I2C_ISR_TC)== RESET)// 标志位
{
if((_time_out--) == 0)
{
return i2c_timeout_callback();
}
}
/* I2C处于空闲状态。则开始I2C通讯进行相关配置 读取,自动结束 */
I2C_TransferHandling(I2C2,Device_address,Len,I2C_AutoEnd_Mode,I2C_Generate_Start_Read);
/*
for(i=0,i<12,i++){
}
*/
Data_Num = 0;
/* 等待数据被接收 */ // Len = 12 Data_Num = 0
while( Data_Num != Len)
{
_time_out = LONG_TIMEOUT;
while(I2C_GetFlagStatus(I2C2,I2C_ISR_RXNE)== RESET)// 标志位
{
if((_time_out--) == 0)
{
return i2c_timeout_callback();
}
}
/* 从I2C2->RXDR寄存器获取数据 */
*buff = I2C_ReceiveData(I2C2);
buff++;//指向下一个地址
Data_Num++;
}
/* 等待STOOPF标志位置位 */
_time_out = LONG_TIMEOUT;
while(I2C_GetFlagStatus(I2C2,I2C_ISR_STOPF)== RESET)// 标志位
{
if((_time_out--) == 0)
{
return i2c_timeout_callback();
}
}
/* 清除STOPCF标志位置位 */
I2C_ClearFlag(I2C2,I2C_ICR_STOPCF);
/* 如果读取结束,则返回OK */
return I2C_OK;
}
#ifndef _I2C_H__
#define _I2C_H__
#include "board_define.h"
#include "var_global.h"
#define SENSOR_I2C_TIMING 0x00200404
#define LONG_TIMEOUT 81920
typedef enum {
I2C_OK = 0,
I2C_ERROR = 1,
I2C_TIMEOUT = 2
}I2C_StatusTypDef;
void i2c_init(void);
I2C_StatusTypDef i2c_reg_write(uint8_t Device_address,uint8_t reg_address,uint8_t data);
I2C_StatusTypDef i2c_read(uint8_t Device_address,uint8_t reg_address,uint8_t Len,uint8_t *buff);
#endif