历史上的今天
今天是:2024年09月26日(星期四)
2021年09月26日 | STM8S GPIO模拟I2C的底层代码
2021-09-26 来源:eefocus
底层代码
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
GPIO初始化设置
这颗STM8S上,具有真·开漏功能的引脚是PB4和PB5,这两个引脚也正是片上I2C外设的默认引脚。端口设置如下:
PB4 :I2C的SCL时钟线,开漏输出模式
PB5 :I2C的SDA数据线,开漏输出模式
SCL和SDA初始化时,推荐选用高阻态输出
/**
* @brief I2C端口初始化
* @param None
* @retval None
*/
void I2C_GPIO_Init(void)
{
GPIO_Init(I2C_PORT, I2C_SDA_PIN, GPIO_MODE_OUT_OD_HIZ_SLOW);
GPIO_Init(I2C_PORT, I2C_SCL_PIN, GPIO_MODE_OUT_OD_HIZ_SLOW);
I2C_SDA_OUT(1);
I2C_SCL_OUT(1);
}
I2C主机向从机发送一个字节,都会等待从机通过SDA线返回一个“已接收(ACK)”指令。此时主机的SDA应设置为输入,而在其他环节中应该保持开漏输出。而根据不同从机的I2C时序,有时也需要将SCL设置为输入。
/**
* @brief SDA设为输出
* @param None
* @retval None
*/
void I2C_SDA_SET_OUTPUT(void)
{
GPIO_Init(I2C_PORT, I2C_SDA_PIN, GPIO_MODE_OUT_OD_HIZ_SLOW);
}
/**
* @brief SCL设为输出
* @param None
* @retval None
*/
void I2C_SCL_SET_OUTPUT(void)
{
GPIO_Init(I2C_PORT, I2C_SCL_PIN, GPIO_MODE_OUT_OD_HIZ_SLOW);
}
/**
* @brief SDA设为输入
* @param None
* @retval None
*/
void I2C_SDA_SET_INPUT(void)
{
GPIO_Init(I2C_PORT, I2C_SDA_PIN, GPIO_MODE_IN_FL_NO_IT);
}
/**
* @brief SCL设为输入
* @param None
* @retval None
*/
void I2C_SCL_SET_INPUT(void)
{
GPIO_Init(I2C_PORT, I2C_SCL_PIN, GPIO_MODE_IN_FL_NO_IT);
}
GPIO输入检测
既然有了SDA或SCL的输入设置,自然需要有判断输入值的函数。
/**
* @brief SDA输入电平检测
* @param None
* @retval 1=输入为高电平 0=输入为低电平
*/
unsigned char I2C_SDA_IN(void)
{
return (!!GPIO_ReadInputPin(I2C_PORT, I2C_SDA_PIN));
}
/**
* @brief SCL输入电平检测
* @param None
* @retval 1=输入为高电平 0=输入为低电平
*/
unsigned char I2C_SCL_IN(void)
{
return (!!GPIO_ReadInputPin(I2C_PORT, I2C_SCL_PIN));
}
模拟I2C代码
包括:
起始条件,结束条件
回从机ACK,回从机NACK: 用于主机从从机读1字节(此时主从的身份对调)后,还要向其发送请继续(ACK) 或 请停下(NACK) 信号
等待从机回ACK: 主机向从机发送1字节后,需要等待从机返回接收到(ACK) ,如果接收到的是 接收到(ACK)
从从机读1字节: 完成读1字节后,需要向从机发送请继续(ACK) 或 请停下(NACK) 信号
向从机写1细节: 完成写1字节后,需要等待从机返回接收到(ACK) 信号。
起始条件,结束条件
/**
* @brief I2C传输开始
* @param None
* @retval None
*/
void I2C_START(void)
{
I2C_SDA_SET_OUTPUT();
I2C_SDA_OUT(1);
I2C_SCL_OUT(1);
Delay_1us(10);/
I2C_SDA_OUT(0);
Delay_1us(10);
I2C_SCL_OUT(0);
Delay_1us(10);
}
/**
* @brief I2C传输结束
* @param None
* @retval None
*/
void I2C_STOP(void)
{
I2C_SDA_SET_OUTPUT();
I2C_SDA_OUT(0);
I2C_SCL_OUT(0);
Delay_1us(10);//
I2C_SCL_OUT(1);
Delay_1us(10);
I2C_SDA_OUT(1);
Delay_1us(10);
}
回从机ACK,回从机NACK
/**
* @brief MCU回复IC ACK信号
* @param None
* @retval None
*/
void I2C_SEND_ACK(void)
{
I2C_SDA_SET_OUTPUT();
I2C_SDA_OUT(0);
Delay_1us(10);//
I2C_SCL_OUT(1);
Delay_1us(10);
I2C_SCL_OUT(0);
Delay_1us(10);
}
/**
* @brief MCU回复NACK信号
* @param None
* @retval None
*/
void I2C_SEND_NACK(void)
{
I2C_SDA_SET_OUTPUT();
I2C_SDA_OUT(1);
// Delay_1us(10);///
I2C_SCL_OUT(1);
Delay_1us(10);
I2C_SCL_OUT(0);
Delay_1us(10);
}
从从机读1字节
/**
* @brief I2C MCU接收1字节
* @param ACK_CHOICE: 数据读取后主机如何回复,I2C_ACK=回复ACK I2C_NACK=回复NACK I2C_JUMP_REPLY=跳过回复
* @retval read_data: 接收的字节
*/
unsigned char I2C_READ_BYTE(unsigned char ACK_CHOICE)
{
unsigned char read_data=0;
I2C_SDA_SET_INPUT();
// I2C_SCL_OUT(0);//
// Delay_1us(10);///
for(unsigned char i=0x80; i!=0; i>>=1)
{
I2C_SCL_OUT(1);
Delay_1us(10);
if(I2C_SDA_IN() == 1)
read_data |= i;
I2C_SCL_OUT(0);
Delay_1us(10);
}
I2C_SDA_SET_OUTPUT();
I2C_SDA_OUT(1);//?????????????????
if(ACK_CHOICE==I2C_ACK) I2C_SEND_ACK();
if(ACK_CHOICE==I2C_NACK) I2C_SEND_NACK();
return read_data;
}
向从机写1字节
/**
* @brief I2C MCU发送1字节
* @param send_data: 发送的字节
* @retval ack回复: I2C_NACK=异常=检测到NACK I2C_ACK=正常=检测到ACK
*/
unsigned char I2C_SEND_BYTE(unsigned char send_data)
{
unsigned char ack=I2C_NACK; //初始值
unsigned char time_out=200; //ACK查询次数
I2C_SDA_SET_OUTPUT();
// I2C_SCL_SET_OUTPUT();
// I2C_SCL_OUT(0);
// Delay_1us(10);/
for(unsigned char i=0x80; i!=0; i>>=1)
{
if(send_data&i) I2C_SDA_OUT(1);
else I2C_SDA_OUT(0);
I2C_SCL_OUT(1);
Delay_1us(10);
I2C_SCL_OUT(0);
Delay_1us(10);
}
//开始ACK查询
I2C_SDA_SET_INPUT();
I2C_SCL_OUT(1);
while(time_out--)
{
if(I2C_SDA_IN()==1)
ack=I2C_NACK;
else
{
ack=I2C_ACK;
break;
}
Delay_1us(1);
}
I2C_SCL_OUT(0);
I2C_SDA_SET_OUTPUT();
I2C_SDA_OUT(1);//???????????????????
return ack;
}
其他代码
上述全部代码位于i2c.c 源文件中,而下列代码则全部位于i2c.h 头文件。
#ifndef __I2C_H
#define __I2C_H
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private defines -----------------------------------------------------------*/
#define I2C_PORT GPIOB
#define I2C_SDA_PIN GPIO_PIN_5
#define I2C_SCL_PIN GPIO_PIN_4
#define I2C_ACK 0 //用于接收:SDA=L=从机有回复 用于发送:回复从机ACK
#define I2C_NACK 1 //用于接收:SDA=H=从机未回复 用于发送:回复从机ACK
#define I2C_JUMP_REPLY 2 //调试用
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void I2C_GPIO_Init(void);
void I2C_SDA_SET_OUTPUT(void);
void I2C_SCL_SET_OUTPUT(void);
void I2C_SDA_SET_INPUT(void);
void I2C_SCL_SET_INPUT(void);
void I2C_SDA_OUT(unsigned char value);
void I2C_SCL_OUT(unsigned char value);
unsigned char I2C_SDA_IN(void);
unsigned char I2C_SCL_IN(void);
void I2C_START(void);
void I2C_STOP(void);
void I2C_SEND_ACK(void);
void I2C_SEND_NACK(void);
unsigned char I2C_READ_BYTE(unsigned char ACK_CHOICE);
unsigned char I2C_SEND_BYTE(unsigned char send_data);
#endif
史海拾趣
|
VC++ --->> WinCE 的问题(对大家应该不会很难) 在VC中用到了一个类CxImage,编译和链接都没有问题,(*.lib的调用也正常)。但是把程序移植到WinCE中,在链接的时候总是出现这样的错误信息,这是什么原因呢? ximage.obj : error LNK2019: 无法解析的外部符号 \"public: void __cdecl CxImage::S ...… 查看全部问答> |
|
前断时间把wince上的usb VIDEO device做好了(是slave的不是host),现在老板又需要做USB AUDIO DEVICE. USB部分已经正常能够发送数据,在电脑上录音设备也能录到声音。但是要真正实现把CE设备的声音通过USB传到电脑上来播放还必须要去修改AUDIO驱 ...… 查看全部问答> |
|
怎么从/PROC/DEVICES中得到动态主设备号?脚本怎么样写,应该写在哪个文件里,怎么样在linux启动时运行这个脚本?谢谢! 怎么从/PROC/DEVICES中得到动态主设备号?脚本怎么样写,应该写在哪个文件里,怎么样在linux启动时运行这个脚本?谢谢!… 查看全部问答> |
|
主机和目标机连接不上什么原因??????????????????????????? 初学VXWORKS不太清楚是不是网卡驱动没有加载?ping也ping不通 我用ifShow显示: lo (unit number 0): Flags: (0x8069) UP LOOPBACK MULTICAST ARP RUNNING Type: SOFTWARE_LOOPBACK ...… 查看全部问答> |
|
求助:如何去除交流采样AD出来的声音信号结果中含有直流分量? 交流采样AD出来的声音信号结果中含有直流分量(可以认为是零漂),即交直流混合电平,感觉上好像这个直流分量会发生变化,可以排除是AD前面电路造成的问题,也就是说可以确认是AD输出的漂移造成的,我想是否可以用数字滤波的方法去掉它,如果可以, ...… 查看全部问答> |
|
现在重新测试,同样的板子,程序也一样。 用149一切正常, 换为2418,电流有1.3ma,而且会经常自动重启。。。 郁闷啊。。。。。。。 lierda的工程师们知道为什么吗?… 查看全部问答> |
|
常见的通讯控制电路里面都包含了,一般的430开发项目直接照搬电路原理图就可以了,包含485通讯,电流、电压、频率数据采集,外部控制,数码管显示、红外遥控等等等功能… 查看全部问答> |
|
复位对于FPGA设计很重要,一些很奇怪而找不到原因的问题很有可能是由于复位造成的,本人就因为没理解好复位情况而受困扰几天。 复位信号可以是高电平也可以是低电平复位。并且电路分外部信号的硬件电路复位和内部信号的软件复位。 外部硬件复 ...… 查看全部问答> |




