STM32F103 硬件IIC彻底解决busy死锁+超时返回+无需中断最高优先级和DMA
#include "IIC_2.h"
#include "DELAY.h"
///*********************************************************************
**********************************
//解决busy死锁问题--但是注意--这里没有超时机制-等于不能保证多主机处理稳
定性
//**********************************************************************
**********************************/
void IS_BUSY(void)
{
u8 i;
while((I2C2->SR2&(1<<1))!=0)//总线忙BUSY!=0就在这里循环等待
{
RCC->APB2ENR|=1<<3; //PORTB时钟使能
//这里只针对IIC2引脚初始化
GPIOB->CRH&=0XFFFF00FF;
GPIOB->CRH|=0X00007700;//PB10-SCK PB11-SDA IO开漏输出0X77
for(i=0;i<10;i++)
{
PBout(10)=~PBout(10);//解决BUSY死锁问题
delay_us(20);
}
PCout(13)=~PCout(13);//led闪起来
IIC_init();
}
}
void IIC_init(void)
{
RCC->APB1ENR|=1<<22; //硬件IIC2的时钟使能
//注意!!AFIO时钟无所谓开启,只有操作
AF(复用功能)的IO重新映射,AFIO时钟才需要开启,并非属于普通IO时钟管理。
RCC->APB2ENR|=1<<3; //PORTB时钟使能
//这里只针对IIC2引脚初始化
GPIOB->CRH&=0XFFFF00FF;
GPIOB->CRH|=0X0000FF00;//PB10-SCK PB11-SDA 全部需要开漏复用输出
0XF
//以下是IIC2的寄存器配置
RCC->APB1RSTR|=1<<22; //复位IIC2寄存器
RCC->APB1RSTR&=~(1<<22);//停止复位IIC2寄存器
I2C2->CR1|=1<<15;//复位IIC2
I2C2->CR1&=~(1<<15);
delay_us(5);
I2C2->CR1&=~(1<<1);//bit-1位 0:I2C模式 1:SMBus模式---配置为IIC模
式。
I2C2->CR1|=1<<10; //bit-10位 0:无应答返回 1:接受到一个字节后返
回一个应答(匹配的地址或数据)
//I2C2->CR2|=1<<10;//bit-10位 ---缓冲器中断使能
//I2C2->CR2|=1<<9;//bit-9位 ---事件中断使能
I2C2->CR2|=1<<8;//bit-8位 ---出错中断使能
I2C2->CR2|=0x24;//bit-5:0位 ---配置为输入时钟36M。
I2C2->OAR1&=~(1<<15);//bit-15位 0:7位从地址 1:10位从地址---
配置为7位从地址。
I2C2->OAR1|=1<<14; //bit-14位 ---要求必须软件保持‘1’
I2C2->OAR1|=0x00; //bit-7:1位 ---7位从模式地址设为0X00-接收
主机信号使用
I2C2->OAR2&=~(1);//bit-0位 0:7位地址模式只识别OAR1 1:7位地址
模式下识别OAR1-2双地址--7位地址模式只识别OAR1。
I2C2->CCR|=1<<15; //bit-15位 ---配置为快速模式的IIC 400kHZ-
所有配置寄存器最好在CR1中的PE使能位关闭的情况设置。
I2C2->CCR&=~(1<<14);//bit-14位 ---快速模式时的占空比设置为2:1
I2C2->CCR|=0x1F; //bit-11:0位 ---配置为快速模式的IIC CCR为
0x1F=31,2*31*27ns+1*31*27ns=2511ns一个周期,398.24771kHZ 无法达到400khz
I2C2->TRISE=0xC; //bit-5:0位 ---配置最大上升时间为324ns
///************** IIC2 NVIC 中断优先级配置*************************/
//使能错误中断
NVIC_Init(0,0,I2C2_ER_IRQn,2);//组2,最高先级-分组不能变
I2C2->CR1|=1; //bit-0位--所有配置寄存器配置妥当后开启PE位---使能IIC2
delay_us(5);
}
#define TimeOut 1000
void I2C_SingleWrite(uint8_t address, uint8_t subAddress, uint8_t data)
{
u16 SR2_STATE=0,i=0;
IS_BUSY();
I2C2->CR1|=1<<8; //产生起始条件 START=1;
i=TimeOut;while((I2C2->SR1&(0x0001))!=0x0001){if(i==0){I2C2->CR1|
=1<<9;return;}else i--;}//SB=1 起始条件已发--读取SR1+写DR可清
除。//IIC_Start();
I2C2->DR=((address<<1)|0);
//IIC_Send_Byte((address<<1)|0);//发送器件地址+写命令
i=TimeOut;while((I2C2->SR1&(0x0002))!=0x0002){if(i==0){I2C2-
>CR1|=1<<9;return;}else i--;}//等待地址发送成功。ADDR=1代表地址发送成功,
收到从机发出的接收地址完成ACK后置位1//IIC_Wait_Ack(); //等待应答
SR2_STATE=I2C2->SR2;//已读SR1-再读-SR2清除ADDR。
SR2_STATE=SR2_STATE;
/*注意,手册说在发送地址阶段不会设置TxE,所以这里TxE=0,不要通过
判断TxE=1来确定收到ACK*/
I2C2->DR=subAddress; //发出第一个DATA,这时候一写入DR马上进入移
位寄存器,TxE还是为1 //IIC_Send_Byte(subAddress); //写寄存器地址-
DATA1
i=TimeOut;while((I2C2->SR1&(0x0080))!=0x0080){if(i==0){I2C2->CR1|
=1<<9;return;}else i--;}//这里等待TxE=1是为了判断DR是否为空。
//IIC_Wait_Ack(); //等待应答
I2C2->DR=data;//发送数据--如果不行就考虑连续写2次DR测试下。
i=TimeOut;while((I2C2->SR1&(0x0084))!=0x0084){if(i==0){I2C2->CR1|
=1<<9;return;}else i--;} //TxE=1且BTF=1 数据寄存器空--移位寄存器已经排空
//IIC_Wait_Ack(); //等待应答
I2C2->CR1|=1<<9; // 产生停止条件 STOP=1;
}
void I2C_MultipleRead(uint8_t address, uint8_t subAddress, uint8_t *
pBuf, uint8_t len)
{
u16 SR2_STATE=0,i=0;
IS_BUSY();
I2C2->CR1|=1<<8; //产生起始条件 START=1;
i=TimeOut;while((I2C2->SR1&(0x0001))!=0x0001){if(i==0){I2C2-
>CR1|=1<<9;return;}else i--;}//SB=1 起始条件已发--读取SR1+写DR可清
除。//IIC_Start();
I2C2->DR=((address<<1)|0);
//IIC_Send_Byte((address<<1)|0);//发送器件地址+写命令
i=TimeOut;while((I2C2->SR1&(0x0002))!=0x0002){if(i==0){I2C2-
>CR1|=1<<9;return;}else i--;}//等待地址发送成功。ADDR=1代表地址发送成功,
收到从机发出的接收地址完成ACK后置位1//IIC_Wait_Ack(); //等待应答
SR2_STATE=I2C2->SR2;//已读SR1-再读-SR2清除ADDR。
SR2_STATE=SR2_STATE;
/*注意,手册说在发送地址阶段不会设置TxE,所以这里TxE=0,不要通过
判断TxE=1来确定收到ACK*/
I2C2->DR=subAddress; //发出第一个DATA,这时候一写入DR马上进入移
位寄存器,TxE还是为1 //IIC_Send_Byte(subAddress); //写寄存器地址-
DATA1
i=TimeOut;while((I2C2->SR1&(0x0084))!=0x0084){if(i==0){I2C2-
>CR1|=1<<9;return;}else i--;} //TxE=1且BTF=1 数据寄存器空--移位寄存器已
经排空 //IIC_Wait_Ack(); //等待应答
/*RESTART-中间插入重开始信号-手册只说10位地址有效-存在错误*/
I2C2->CR1|=1<<8; //重开始信号-起始条件 START=1;
i=TimeOut;while((I2C2->SR1&(0x0001))!=0x0001){if(i==0){I2C2-
>CR1|=1<<9;return;}else i--;}//SB=1 起始条件已发--读取SR1+写DR可清
除。//IIC_Start();
I2C2->DR=((address<<1)|1);//发送器件地址+读命令
I2C2->CR1|=1<<10;//开启应答-------->>
i=TimeOut;while((I2C2->SR1&(0x0002))!=0x0002){if(i==0){I2C2-
>CR1|=1<<9;return;}else i--;}//等待地址发送成功。ADDR=1代表地址发送成功,
收到从机发出的接收地址完成ACK后置位1//IIC_Wait_Ack(); //等待应答
SR2_STATE=I2C2->SR2;//已读SR1-再读-SR2清除ADDR-代表收到地址ACK
while(len)
{
if(len==1)
{
I2C2->CR1&=~(1<<10);//NACK
I2C2->CR1|=1<<9; // 请求产生停止条件
STOP=1,注意位置-手册所需要当前字节传输完成ACK之前----执行停止请求后不要
设置CR1---->>
i=TimeOut;while((I2C2->SR1&(0x0040))!
=0x0040){if(i==0){I2C2->CR1|=1<<9;return;}else i--;}// RxNE=1 数据寄存器
接收到数据
*pBuf=I2C2->DR;//读数据,发送nACK
}
else
{
i=TimeOut;while((I2C2->SR1&(0x0040))!
=0x0040){if(i==0){I2C2->CR1|=1<<9;return;}else i--;}// RxNE=1 数据寄存器
接收到数据
*pBuf=I2C2->DR; //读数据,发送ACK
}
len--;
pBuf++;
}
}
void I2C_MultipleWrite(uint8_t address, uint8_t subAddress, uint8_t *
pBuf, uint8_t len)
{
u16 SR2_STATE=0,i=0;
IS_BUSY();
I2C2->CR1|=1<<8; //产生起始条件 START=1;
i=TimeOut;while((I2C2->SR1&(0x0001))!=0x0001){if(i==0){I2C2-
>CR1|=1<<9;return;}else i--;}//SB=1 起始条件已发--读取SR1+写DR可清
除。//IIC_Start();
I2C2->DR=((address<<1)|0);
//IIC_Send_Byte((address<<1)|0);//发送器件地址+写命令
i=TimeOut;while((I2C2->SR1&(0x0002))!=0x0002){if(i==0){I2C2-
>CR1|=1<<9;return;}else i--;}//等待地址发送成功。ADDR=1代表地址发送成功,
收到从机发出的接收地址完成ACK后置位1//IIC_Wait_Ack(); //等待应答
SR2_STATE=I2C2->SR2;//已读SR1-再读-SR2清除ADDR。
SR2_STATE=SR2_STATE;
/*注意,手册说在发送地址阶段不会设置TxE,所以这里TxE=0,不要通过
判断TxE=1来确定收到ACK*/
I2C2->DR=subAddress; //发出第一个DATA,这时候一写入DR马上进入移
位寄存器,TxE还是为1 //IIC_Send_Byte(subAddress); //写寄存器地址-
DATA1
i=TimeOut;while((I2C2->SR1&(0x0080))!=0x0080){if(i==0){I2C2->CR1|
=1<<9;return;}else i--;}//这里等待TxE=1是为了判断DR是否为空。
//IIC_Wait_Ack(); //等待应答
while(len)
{
if(len==1)
{
I2C2->DR=*pBuf;//发送最后一个Buf的数据
i=TimeOut;while((I2C2->SR1&(0x0084))!=0x0084){if(i==0){I2C2-
>CR1|=1<<9;return;}else i--;} //TxE=1且BTF=1 数据寄存器空--移位寄存器已
经排空 //IIC_Wait_Ack(); //等待应答
I2C2->CR1|=1<<9; // 请求产生停止条件
STOP=1--执行停止请求后不要设置CR1---->>
}
else
{
I2C2->DR=*pBuf;//发送buff的数据
i=TimeOut;while((I2C2->SR1&(0x0080))!=0x0080)
{if(i==0){I2C2->CR1|=1<<9;return;}else i--;}//这里等待TxE=1是为了判断DR
是否为空。 //IIC_Wait_Ack(); //等待应答
}
len--;
pBuf++;
}
}
///*********************************************************************
**********************************
//** 函数名称: I2C1_ER_IRQHandler
//** 功能描述: I2C错误中断服务
//** 返 回: 无
//**********************************************************************
**********************************/
void I2C2_ER_IRQHandler(void)
{
u8 i;
RCC->APB2ENR|=1<<3; //PORTB时钟使能
//这里只针对IIC2引脚初始化
GPIOB->CRH&=0XFFFF00FF;
GPIOB->CRH|=0X00007700;
for(i=0;i<10;i++)
{
PBout(10)=~PBout(10);//解决BUSY死锁问题
delay_us(20);
}
PCout(13)=~PCout(13);//led闪起来
delay_ms(200);
IIC_init();
I2C2->SR1&=0x00FF;//软件写0清除
}
相关推荐
产业园区如何高效对接企业技术需求与高校科研成果?.docx
科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。
国央企创新负责人如何快速掌握本地科技资源分布与匹配情况?.docx
科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。
国央企创新负责人如何实现科技成果的精准识别与高效筛选?.docx
科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。
数据挖掘实战:决策树 + 聚类 + 关联规则,零 Key 离线可跑(Python 源码)
数据挖掘实战包。用 Python 标准库实现 CART 风格决策树、K-Means 聚类与 Apriori 关联规则,在虚构「星河便利店」会员表和购物篮上跑通分类、分群与购物篮分析,并给出准确率、轮廓系数、支持度/置信度/提升度。零第三方依赖、零 API Key 即可离线跑通。含 4 个样例、离线冒烟、中文 README(含「使用方法」)。均为作者原创可运行源码。MIT。作者 blog.csdn.net/mtl1994
SpringBoot+Vue+Mysql社区医院信息平台(源码+文档)
SpringBoot+Vue+Mysql学生宿舍信息管理系统 WEB端软件项目(源码+文档) 项目包含:①完整源码(后端+管理后台+用户前台);②数据库脚本文件;③万字论文文档;④开题报告;⑤答辩PPT;⑥项目运行视频教程。 项目架构: B/S 架构、MVC 分层设计 技术栈: Java、MySQL、SpringBoot、MyBatis-Plus、Token 权限校验、管理后台 Vue+ElementUI+ECharts、用户前台 Layui+jQuery、Maven 构建。 一、角色设计 学生用户: 注册登录、浏览宿舍信息、查询宿舍安排、在线报修、缴费查询、失物招领、桶装水预订、评论交流、收藏等。 商家用户: 注册登录、桶装水品牌与商品信息维护、预订订单查看与处理。 维修人员: 注册登录、查看待处理报修、接单维修、填写报修处理结果与进度反馈。 管理员: 学生管理、班级管理、宿舍信息管理、宿舍安排管理、报修处理管理、缴费信息管理、卫生检查与文明宿舍管理、失物招领管理、桶装水与商家管理、维修人员管理、公告资讯与轮播图管理等。 二、前台功能模块(学生端) 1. 首页展示:轮播图、宿舍公告、最新动态推荐、常用服务快速入口 2. 宿舍信息模块:宿舍列表、楼栋与房间条件筛选、宿舍详情查看、我的宿舍安排查询 3. 在线报修模块:在线提交宿舍设施报修申请、上传故障描述、查看报修进度与维修处理结果 4. 缴费模块:水电等缴费记录查询、缴费状态查看 5. 卫生检查与文明宿舍:宿舍卫生检查结果公示、文明宿舍展示 6. 失物招领模块:失物信息发布、招领信息发布、详情查看、评论互动 7. 桶装水预订:桶装水品牌与商品浏览、在线预订、我的预订记录查询 8. 假期留宿:假期留校申请提交、申请记录查询 9. 评论与收藏:信息评论、查看他人评论、评论回复互动、收藏感兴趣的内容 10. 个人中心...


单片机/工控

