本文共 11936 字,大约阅读时间需要 39 分钟。
翻遍了网络,国产MCU的资源还是较少,就贡献一个吧
使用了国产的RT-thread操作系统+M0的单片机,在灵动微MM32SPIN27上实现的硬件I2C从机,有需要的朋友拿去,根据情况改改可用
1.头文件
/******************************************************************************************
* 文件 名: drv_i2c_slave.h * 文件描述: i2c从机驱动程序头文件 * 文件版本: V1.2 * 日 期: 2021/04/19 * 作 者: 何江 * 版本记录 * 2021/04/19:第一次发布 * * ******************************************************************************************/ #ifndef __DRV_I2C_SLAVE_H__ #define __DRV_I2C_SLAVE_H__ /****************************************************************************************** 头文件包含 *******************************************************************************************/ #include "HAL_device.h" #include "HAL_conf.h" #include "config.h" /****************************************************************************************** 宏定义 *******************************************************************************************/ #define USING_I2C1 1 #define USING_I2C2 0#define I2C_SLAVE_WADDR 0xA0
#define I2C_SLAVE_RADDR 0xA1#define I2C_SLAVE_TX_BUF_SIZE 36
#define I2C_SLAVE_RX_BUF_SIZE 36 /****************************************************************************************** 全局变量 *******************************************************************************************/ //i2c工作状态机 typedef enum{ I2C_IDLE, //I2C空闲 I2C_ADDR_MATCH, //地址匹配 I2C_RECV_DATA, //接收数据 I2C_TRAN_DATA, //发送数据 }i2c_sstatus_t;//i2c设备从机属性结构
typedef struct{ I2C_TypeDef *device; i2c_sstatus_t status; int8u_t recv_buffer[I2C_SLAVE_RX_BUF_SIZE]; int8u_t tran_buffer[I2C_SLAVE_TX_BUF_SIZE]; int8u_t *precv_buf; int8u_t *ptran_buf; int16s_t recv_count; int16s_t tran_count; }i2c_slave_t;#if (USING_I2C1)
extern i2c_slave_t i2c1_slave_dev; #endif#if (USING_I2C2)
extern i2c_slave_t i2c2_slave_dev; #endif /****************************************************************************************** 功能函数 *******************************************************************************************/ void i2c_slave_init(i2c_slave_t *pdev,int8u_t numb);int16s_t i2c_slave_read_recv_data(i2c_slave_t *pdev,int8u_t *pd);
int16s_t i2c_slave_write_txbuffer_nbyte(i2c_slave_t *pdev,int16s_t index,int8u_t *pd,int16s_t count);
int16s_t i2c_slave_read_txbuffer_nbyte(i2c_slave_t *pdev,int16s_t index,int8u_t *pd,int16s_t count);
#endif
/******************************************************************************************
end file *******************************************************************************************/2.驱动C文件
/******************************************************************************************
* 文 件 名: drv_i2c_slave.c * 文件描述: i2c从机驱动程序文件 * 文件版本: V1.0 * 日 期: 2020/12/14 * 作 者: 何江 * 版本记录 * 2020/12/14: 第一次发布 *******************************************************************************************/
/****************************************************************************************** 头文件包含 *******************************************************************************************/ #include "drv_i2c_slave.h" #include <rthw.h> #include <rtthread.h> /****************************************************************************************** 宏定义 *******************************************************************************************/ /****************************************************************************************** 功能函数 *******************************************************************************************/ /****************************************************************************************** I2C从机GPIO初始化 *******************************************************************************************/ #if (USING_I2C1) i2c_slave_t i2c1_slave_dev; static void I2C1_Configuration(void) { GPIO_InitTypeDef GPIO_InitStruct; NVIC_InitTypeDef NVIC_InitStructure; /* Enable GPIOA clock */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //复用功能选择 GPIO_PinAFConfig( GPIOA ,GPIO_PinSource11, GPIO_AF_5); GPIO_PinAFConfig( GPIOA ,GPIO_PinSource12, GPIO_AF_5); //GPIO配置 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(GPIOA , &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(GPIOA , &GPIO_InitStruct); //配置i2c中断 NVIC_InitStructure.NVIC_IRQChannel = I2C1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } #endif /****************************************************************************************** I2C_SendSlaveAddress 设置从机模式的本机地址 *******************************************************************************************/ static void I2C_SendSlaveAddress(I2C_TypeDef* i2c, u8 addr) { WRITE_REG(i2c->IC_SAR, addr >> 1); } /****************************************************************************************** 函数名称: i2c_slave_init功能描述: I2C 从机初始化配置
输 入: pdev 从机设备
numb i2c外设号,有的mcu支持2路输 出: 无
*******************************************************************************************/ void i2c_slave_init(i2c_slave_t *pdev,int8u_t numb) { I2C_TypeDef *pi2c; I2C_InitTypeDef I2C_InitStruct; if(numb == 1){ #if (USING_I2C1) pi2c = I2C1; I2C1_Configuration(); #endif }else if(numb == 2){ #if (USING_I2C2) pI2C = I2C2; I2C2_Configuration(); #endif }else{ return ; } pdev->device = pi2c; RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE); I2C_StructInit(&I2C_InitStruct); /* I2C configuration */ I2C_InitStruct.I2C_Mode = I2C_Mode_SLAVE; I2C_InitStruct.I2C_OwnAddress = 0; I2C_InitStruct.I2C_Speed = I2C_Speed_STANDARD; I2C_InitStruct.I2C_ClockSpeed = 100000; I2C_Init(pi2c, &I2C_InitStruct); I2C_ITConfig(pi2c,I2C_IT_RD_REQ|I2C_IT_STOP_DET,ENABLE); I2C_ITConfig(pi2c,I2C_IT_RX_FULL,ENABLE); //记得打开SLAVE使能标志 pi2c->IC_CON &= (~IC_SLAVE_DISABLE); I2C_Cmd(pi2c, ENABLE); //从机匹配地址 I2C_SendSlaveAddress(pi2c,I2C_SLAVE_WADDR); pdev->status = I2C_IDLE; pdev->ptran_buf = pdev->tran_buffer; pdev->precv_buf = pdev->recv_buffer; pdev->tran_count = I2C_SLAVE_TX_BUF_SIZE; pdev->recv_count = 0; } /******************************************************************************************* 函数名称: i2c_slave_read_recv_data功能描述: 从I2C缓冲区中读取所有数据,并清除接收数据计数器
输 入: pdev i2c结构
pd 保存数据的缓冲区输 出: 实际接收到的数据个数
*******************************************************************************************/ int16s_t i2c_slave_read_recv_data(i2c_slave_t *pdev,int8u_t *pd) { int16s_t count; rt_base_t level; if(pd == _NULL || pdev == _NULL) return -1; if(pdev->status == I2C_IDLE){ level = rt_hw_interrupt_disable(); for(count = 0; count < pdev->recv_count; count++){ pd[count] = pdev->recv_buffer[count]; } pdev->recv_count = 0; pdev->precv_buf = pdev->recv_buffer; rt_hw_interrupt_enable(level); }else{ count = 0; } return count; } /******************************************************************************************* 函数名称: i2c_slave_write_txbuffer_nbyte功能描述: 设置修改I2C发送缓冲区中数据,并更新发送数量
输 入: pdev i2c结构
index 缓冲区数组索引 pd 要写入数据的缓冲区 count 要写入数据的个数输 出: 实际写入的数据个数
*******************************************************************************************/ int16s_t i2c_slave_write_txbuffer_nbyte(i2c_slave_t *pdev,int16s_t index,int8u_t *pd,int16s_t count) { int16s_t i; rt_base_t level; if(pd == _NULL || pdev == _NULL || ((index + count) >= I2C_SLAVE_TX_BUF_SIZE)) return -1; //写入缓冲区完成之前不允许被i2c主机来读取 //__disable_irq(); level = rt_hw_interrupt_disable(); for(i = index; i < (index + count); i++){ pdev->tran_buffer[i] = pd[i]; } //__enable_irq(); //设置i2c发送缓冲区的数量 pdev->tran_count = index + count; rt_hw_interrupt_enable(level); return i; } /******************************************************************************************* 函数名称: i2c_slave_read_txbuffer_nbyte功能描述: 读取I2C发送缓冲区中数据,一般用来与应用程序中作比较用
输 入: pdev i2c结构
index 缓冲区数组索引 pd 要写入数据的缓冲区 count 要写入数据的个数输 出: 实际读取的数据个数
*******************************************************************************************/ int16s_t i2c_slave_read_txbuffer_nbyte(i2c_slave_t *pdev,int16s_t index,int8u_t *pd,int16s_t count) { int16s_t i; if(pd == _NULL || pdev == _NULL || ((index + count) >= I2C_SLAVE_TX_BUF_SIZE)) return -1; for(i = 0; i < count; i++){ pd[i] = pdev->tran_buffer[index]; } return i; }/*******************************************************************************************
函数名称: i2c_slave_isr功能描述: I2C中断函数
输 入: pdev i2c结构
输 出: 无
*******************************************************************************************/ void i2c_slave_isr(i2c_slave_t *pdev) { //主机写,直接存入缓冲区 if(I2C_GetITStatus(pdev->device, I2C_IT_RX_FULL)){ pdev->status = I2C_RECV_DATA; while(I2C_GetFlagStatus(pdev->device, I2C_STATUS_FLAG_RFNE)){ if(pdev->recv_count < I2C_SLAVE_RX_BUF_SIZE){ *pdev->precv_buf++ = I2C_ReceiveData(pdev->device); pdev->recv_count++; }else{ //用于清除I2C_IT_RX_FULL中断 I2C_ReceiveData(pdev->device); } } } //总线停止中断,STOP中断后i2c slave进入空闲状态 if(I2C_GetITStatus(pdev->device, I2C_IT_STOP_DET)){ I2C_ITConfig(pdev->device,I2C_IT_TX_EMPTY,DISABLE); I2C_ClearITPendingBit(pdev->device, I2C_IT_TX_EMPTY); I2C_ClearITPendingBit(pdev->device, I2C_IT_STOP_DET); I2C_ClearFlag(pdev->device, I2C_IT_TX_EMPTY); I2C_ClearFlag(pdev->device, I2C_IT_TX_ABRT); pdev->status = I2C_IDLE; } //主机请求读,只会进一次 if(I2C_GetITStatus(pdev->device, I2C_IT_RD_REQ)){ I2C_ClearITPendingBit(pdev->device, I2C_IT_RD_REQ); //打开发送寄存器空中断 I2C_ITConfig(pdev->device,I2C_IT_TX_EMPTY,ENABLE); //复位发送缓冲区指针 pdev->ptran_buf = pdev->tran_buffer; pdev->tran_count = I2C_SLAVE_TX_BUF_SIZE; pdev->status = I2C_TRAN_DATA; } switch(pdev->status){ case I2C_IDLE: if(I2C_GetITStatus(pdev->device, I2C_IT_TX_EMPTY)){ I2C_ITConfig(pdev->device,I2C_IT_TX_EMPTY,DISABLE); I2C_ClearITPendingBit(pdev->device, I2C_IT_TX_EMPTY); } break; case I2C_RECV_DATA: break; case I2C_TRAN_DATA: if(I2C_GetITStatus(pdev->device, I2C_IT_TX_EMPTY)){ I2C_ClearITPendingBit(pdev->device, I2C_IT_TX_EMPTY); if(pdev->tran_count > 0){ I2C_SendData(pdev->device,*pdev->ptran_buf++); pdev->tran_count--; //缓冲区数据发送完毕,退出发送 if(pdev->tran_count == 0){ pdev->ptran_buf = pdev->tran_buffer; pdev->tran_count = I2C_SLAVE_TX_BUF_SIZE; //中止发送 I2C_GenerateSTOP(I2C1, ENABLE); pdev->status = I2C_IDLE; break; } }else{ //复位发送缓冲区指针 pdev->ptran_buf = pdev->tran_buffer; pdev->tran_count = I2C_SLAVE_TX_BUF_SIZE; //中止发送 I2C_GenerateSTOP(I2C1, ENABLE); pdev->status = I2C_IDLE; } } break; default: break; } } /******************************************************************************* * Function Name : I2C1_IRQHandler * Description : This function handles I2C1 global interrupt request. * Input : None * Output : None * Return : None *******************************************************************************/ void I2C1_IRQHandler(void) { #if (USING_I2C1) i2c_slave_isr(&i2c1_slave_dev); #endif } /****************************************************************************************** endfile *******************************************************************************************/3.使用方法
初始化
i2c_slave_init(&i2c1_slave_dev,1);
处理例程
/******************************************************************************************
i2c_slave_proc *******************************************************************************************/ static void i2c_slave_proc(void) { int8u_t buffer[I2C_SLAVE_RX_BUF_SIZE]; int16s_t len; len = i2c_slave_read_recv_data(&i2c1_slave_dev,buffer); if(len > 0){ switch(buffer[0]){ case FLW4C_CONF_REG: //控制捕获命令 break; case FLW4C_DOUT_PWR_REG: if(buffer[1] == 1){ GPIO_SetBits(GPIOA,GPIO_Pin_15); }else{ GPIO_ResetBits(GPIOA,GPIO_Pin_15); } break; } }else{ int32u_t ufreq = 100, count = 150; int8u_t *pd = buffer; rt_memcpy(pd,&ufreq,4);pd += 4; rt_memcpy(pd,&count,4);pd += 4; rt_memcpy(pd,&ufreq,4);pd += 4; rt_memcpy(pd,&count,4);pd += 4; rt_memcpy(pd,&ufreq,4);pd += 4; rt_memcpy(pd,&count,4);pd += 4; rt_memcpy(pd,&ufreq,4);pd += 4; rt_memcpy(pd,&count,4); i2c_slave_write_txbuffer_nbyte(&i2c1_slave_dev,0,buffer,32); } }
转载地址:http://bmlvz.baihongyu.com/