STM8S GPIO模拟I2C的底层代码

发布者:SparklingSoul最新更新时间:2021-09-26 来源: eefocus关键字:STM8S  GPIO  模拟I2C 手机看文章 扫描二维码
随时随地手机看文章

底层代码

你好! 这是你第一次使用 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

关键字:STM8S  GPIO  模拟I2C 引用地址:STM8S GPIO模拟I2C的底层代码

上一篇:stm8s103-PWM输出与输入捕获
下一篇:基于IAR开发环境的STM8S模拟IIC代码

推荐阅读最新更新时间:2024-10-28 11:05

stm8s的内部时钟切换
要用到stm8s105k6的内部128K低速时钟,调试不是蛮顺利,特此记录下。 从内部16M时钟切换至内部128K时钟,配置如下: void Clk_Config(void) { CLK_CKDIVR= 0x00; //系统时钟 1 分频 while(!(CLK_ICKR & 0x02)); //等待 HSI 准备好 CLK_SWCR|=0x02; //开启切换 CLK_ICKR|=0x08; //开启LSI while(!(CLK_ICKR&0x10)); //LSI准备就绪 CLK_SWR=0xd2; //LSR
[单片机]
<font color='red'>stm8s</font>的内部时钟切换
【STM32基础学习】八种GPIO模式总结
八种IO模式再现 (1)GPIO_Mode_AIN 模拟输入 (2)GPIO_Mode_IN_FLOATING 浮空输入 (3)GPIO_Mode_IPD 下拉输入 (4)GPIO_Mode_IPU 上拉输入 (5)GPIO_Mode_Out_OD 开漏输出 (6)GPIO_Mode_Out_PP 推挽输出 (7)GPIO_Mode_AF_OD 复用开漏输出 (8)GPIO_Mode_AF_PP 复用推挽输出 解释速查 浮空输入_IN_FLOATING 浮空输入,通常用作KEY识别 带上拉输入_IPU IO内部上拉电阻输入,默认电平是高 带下拉输入_IPD IO内部下拉电阻输入,默认电平是低。 模拟输入_AIN
[单片机]
STM32入门学习之GPIO(STM32F030F4P6基于CooCox IDE)
依然,直接上代码 #include stm32f0xx.h #include stm32_lib/inc/stm32f0xx_rcc.h #include stm32_lib/inc/stm32f0xx_gpio.h int main(void) { //IOPAEN=1,使能GPIOA的时钟 RCC- AHBENR |= RCC_AHBENR_GPIOAEN; //设置IO口工作模式,GPIOA_MODER4=0x01,通用IO口 GPIOA- MODER |= GPIO_MODER_MODER4_0; GPIOA- MODER &= ~GPIO_MODER_MODER4_1; //设置输出类型,GPIO
[单片机]
GPIO简介
一、GPIO是什么 GPIO(general porpose intput output):通用输入输出端口的简称。可以通过软件控制其输出和输入。stm32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通信,控制以及数据采集的功能。 二、STM32引脚分类 电源管脚: 引脚图中的 VDD、VSS、VREF+、VREF-、VSSA、VDDA 等都属于电源引脚。 晶振管脚:引脚图中的 PC14、PC15 和 OSC_IN、OSC_OUT 都属于晶振引脚,不过它们还可以作为普通引脚使用。 复位管脚: 引脚图中的 NRST 属于复位引脚,不做其他功能使用。 下载引脚:引脚图中的 PA13、PA14、PA15、PB
[单片机]
<font color='red'>GPIO</font>简介
ARM学习笔记015之GPIO(汇编、key、led接线、int main、-wall)
1、makefile中警告命令:用-Wall,而不能都是大写或小写。如果是都小写则出现如下错误提示: arm-none-linux-gnueabi-gcc: unrecognized option '-wall' 2、c文件中main函数必须是int型,不能是void型,不然会: warning: return type of 'main' is not 'int' 3、汇编语句中关于地址的需要用=号: ldr r0,=0x56000000 //没有等号就会出现这样的错误 crt0.s: Assembler messages:crt0.s:8: Err
[单片机]
ARM学习笔记015之<font color='red'>GPIO</font>(汇编、key、led接线、int main、-wall)
STM32 GPIO 寄存器配置
一.CRH和CRL的使用:fficeffice / CRH和CRL的使用基本相同,CRH用于控制GPIOX(X表示A---G)的高8位(Pin15---Pin8),而CRL用于控制GPIOX(X表示A---G)的低8位(Pin7----Pin0)。 二.ODR的使用: 1. RCC- APB2ENR|=1 2; //使能PORTA时钟 GPIOA- CRH&=0XFFFFFFF0;//清除该位原来的设置 GPIOA- CRH|=0X00000003;//PA8 推挽输出 GPIOA- ODR|=
[单片机]
数字可视对讲技术探讨
  引言      20世纪60年代,电视改变了人们的生活,出现了“电视一代”;80年代,电脑改变了人们的工作方式,促成了“电脑一代”;90年代,互联网改变了人们获取信息的方式,诞生了“网络一代”。      进入21世纪,数字化的生活方式将无处不再,最终会全面进入每个人的家庭,数字家庭的浪潮已经汹涌澎湃。      传统的数字家庭中心之争:PC中心论、TV中心论及SetBox中心论,其优势和劣势都很明显,就单一产品而言都难以独自承担数字家庭的重任。近年来市场上出现了另一产品逐渐承担了数字家庭越来越多的功能和责任,这就是数字可视对讲。传统的楼宇可视对讲产品逐渐往数字化,网络化、智能化的方向发展,可视对讲产品除了担当可视
[安防电子]
51单片机(六)—— GPIO控制多路LED
本文中,我们对多路LED进行控制,硬件电路如下图所示 在《51单片机(五)—— GPIO点亮一个LED》中,已经对这个电路做了详细介绍,这里不再详述。 在这个实验中,我们采用两种方法对多路LED进行控制,实验是需要把J21接口的8个引脚与单片机的P0口的8个引脚分别连接在一起。 方法一: 实现代码如下所示 #include reg52.h //包含头文件,一般情况不需要改动, sbit LED1=P0^0; //用sbit关键字 定义LED1到P00端口, sbit LED2=P0^1; sbit LED3=P0^2; sbit LED4=P0^3; sbit LED5=P0^4; sbit LED6=P0^5
[单片机]
51单片机(六)—— <font color='red'>GPIO</font>控制多路LED
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved