当前位置: 首页 > article >正文

C++例程:使用I/O模拟IIC接口(6)

完整的STM32F405代码工程I2C驱动源代码跟踪
一)myiic.c

#include "myiic.h"
#include "delay.h"	
#include "stm32f4xx_rcc.h"						  

//初始化IIC
void IIC_Init(void)
{			
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
	  //SCL_1->GPIOA0,SDA_1->GPIOA1
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
	SCL_1=1;
	SDA_1=1;
}

//产生IIC1起始信号
void IIC1_Start(void)
{
	SDA1_OUT();     //sda线输出
	SDA_1=1;	  	  
	SCL_1=1;
	delay_us(4);
	delay_us(4);
 	SDA_1=0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	delay_us(4);
	SCL_1=0;//钳住I2C总线,准备发送或接收数据 
}
//产生IIC停止信号
void IIC1_Stop(void)
{
	SDA1_OUT();//sda线输出
	SCL_1=0;
	SDA_1=0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	delay_us(4);
	SCL_1=1; 
	delay_us(4);
	delay_us(4);
	SDA_1=1;//发送I2C总线结束信号
	delay_us(4);
  delay_us(4);	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC1_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA1_IN();      //SDA设置为输入  
	SDA_1=1;delay_us(1);	   
	SCL_1=1;delay_us(1);	 
	while(READ_SDA1)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC1_Stop();
			return 1;
		}
	}
	SCL_1=0;//时钟输出0 	   
	return 0;  
} 

//产生ACK应答
void IIC1_Ack(void)
{
	SCL_1=0;
	SDA1_OUT();
	SDA_1=0;
	delay_us(2);
	delay_us(2);
	SCL_1=1;
	delay_us(2);
	delay_us(2);
	SCL_1=0;
}

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC1_Send_Byte(u8 txd)
{                        
    u8 t;   
	  SDA1_OUT(); 	    
    SCL_1=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        SDA_1=(txd&0x80)>>7;
        txd<<=1; 	  
				delay_us(2);   //对TEA5767这三个延时都是必须的
				delay_us(2);
				SCL_1=1;
				delay_us(2); 
				delay_us(2);
				SCL_1=0;	
				delay_us(2);
				delay_us(2);
    }	 
} 
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC1_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA1_IN();//SDA设置为输入
  for(i=0;i<8;i++ )
	{
			 SCL_1=0; 
			 delay_us(2);
			 delay_us(2);
			 SCL_1=1;
			 receive<<=1;
			 if(READ_SDA1)receive++;   
			 delay_us(1); 
			 delay_us(1);
    }					 
    if (!ack)
        IIC1_NAck();//发送nACK
    else
        IIC1_Ack(); //发送ACK   
    return receive;
}

二) myiic.h

#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h" 
//	  	   		   
//PA1输入模式 输出模式
#define SDA1_IN()  {GPIOA->MODER&=~(3<<(1*2));GPIOA->MODER|=0<<1*2;}	
#define SDA1_OUT() {GPIOA->MODER&=~(3<<(1*2));GPIOA->MODER|=1<<1*2;} 
//IO操作函数	 
#define SCL_1    PAout(0) //SCL
#define SDA_1    PAout(1) //SDA	 
#define READ_SDA1   PAin(1)  //输入SDA 
//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口	
void IIC1_Start(void);				//发送IIC开始信号
void IIC1_Stop(void);	  			//发送IIC停止信号
void IIC1_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC1_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC1_Wait_Ack(void); 				//IIC等待ACK信号
void IIC1_Ack(void);					//IIC发送ACK信号
void IIC1_NAck(void);				//IIC不发送ACK信号
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
#endif

三) sys.h

#ifndef __SYS_H
#define __SYS_H	 
#include "stm32f4xx.h" 
//	 																  	 
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 
#endif

四)stm32f4xx.h

#ifndef __STM32F4xx_H
#define __STM32F4xx_H

#ifdef __cplusplus
 extern "C" {
#endif /* __cplusplus */

typedef struct
{
   /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t MODER;   
  /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OTYPER;  
  /*!< GPIO port output speed register,       Address offset: 0x08      */ 
  __IO uint32_t OSPEEDR;  
   /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t PUPDR;   
   /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t IDR;   
  /*!< GPIO port output data register,        Address offset: 0x14      */  
  __IO uint32_t ODR;    
  /*!< GPIO port bit set/reset low register,  Address offset: 0x18      */  
  __IO uint16_t BSRRL;   
  /*!< GPIO port bit set/reset high register, Address offset: 0x1A      */ 
  __IO uint16_t BSRRH;  
   /*!< GPIO port configuration lock register, Address offset: 0x1C      */  
  __IO uint32_t LCKR;    
   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
  __IO uint32_t AFR[2];  
} GPIO_TypeDef;
/*!< Peripheral base address in the alias region        */
#define PERIPH_BASE           ((uint32_t)0x40000000) 
/*!< Peripheral memory map */
#define AHB1PERIPH_BASE       (PERIPH_BASE + 0x00020000)
/*!< AHB1 peripherals */
#define GPIOA_BASE            (AHB1PERIPH_BASE + 0x0000)

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)


#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __STM32F4xx_H */

五)stm32f4xx_rcc.h

#ifndef __STM32F4xx_RCC_H
#define __STM32F4xx_RCC_H

#ifdef __cplusplus
 extern "C" {
#endif

#define RCC_AHB1Periph_GPIOD             ((uint32_t)0x00000008)

void  RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState);

#ifdef __cplusplus
}
#endif

#endif /* __STM32F4xx_RCC_H */

六)stm32f4xx_rcc.c

#include "stm32f4xx_rcc.h"
/**
  * @brief  Enables or disables the AHB1 peripheral clock.
  * @note   After reset, the peripheral clock (used for registers read/write access)
  *         is disabled and the application software has to enable this clock before 
  *         using it.   
  * @param  RCC_AHBPeriph: specifies the AHB1 peripheral to gates its clock.
  *          This parameter can be any combination of the following values:
  *            @arg RCC_AHB1Periph_GPIOA:       GPIOA clock
  *            @arg RCC_AHB1Periph_GPIOB:       GPIOB clock 
  *            @arg RCC_AHB1Periph_GPIOC:       GPIOC clock
  *            @arg RCC_AHB1Periph_GPIOD:       GPIOD clock
  *            @arg RCC_AHB1Periph_GPIOE:       GPIOE clock
  *            @arg RCC_AHB1Periph_GPIOF:       GPIOF clock
  *            @arg RCC_AHB1Periph_GPIOG:       GPIOG clock
  *            @arg RCC_AHB1Periph_GPIOG:       GPIOG clock
  *            @arg RCC_AHB1Periph_GPIOI:       GPIOI clock
  *            @arg RCC_AHB1Periph_GPIOJ:       GPIOJ clock (STM32F42xxx/43xxx devices) 
  *            @arg RCC_AHB1Periph_GPIOK:       GPIOK clock (STM32F42xxx/43xxx devices)  
  *            @arg RCC_AHB1Periph_CRC:         CRC clock
  *            @arg RCC_AHB1Periph_BKPSRAM:     BKPSRAM interface clock
  *            @arg RCC_AHB1Periph_CCMDATARAMEN CCM data RAM interface clock
  *            @arg RCC_AHB1Periph_DMA1:        DMA1 clock
  *            @arg RCC_AHB1Periph_DMA2:        DMA2 clock
  *            @arg RCC_AHB1Periph_DMA2D:       DMA2D clock (STM32F429xx/439xx devices)  
  *            @arg RCC_AHB1Periph_ETH_MAC:     Ethernet MAC clock
  *            @arg RCC_AHB1Periph_ETH_MAC_Tx:  Ethernet Transmission clock
  *            @arg RCC_AHB1Periph_ETH_MAC_Rx:  Ethernet Reception clock
  *            @arg RCC_AHB1Periph_ETH_MAC_PTP: Ethernet PTP clock
  *            @arg RCC_AHB1Periph_OTG_HS:      USB OTG HS clock
  *            @arg RCC_AHB1Periph_OTG_HS_ULPI: USB OTG HS ULPI clock
  * @param  NewState: new state of the specified peripheral clock.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_RCC_AHB1_CLOCK_PERIPH(RCC_AHB1Periph));

  assert_param(IS_FUNCTIONAL_STATE(NewState));
  if (NewState != DISABLE)
  {
    RCC->AHB1ENR |= RCC_AHB1Periph;
  }
  else
  {
    RCC->AHB1ENR &= ~RCC_AHB1Periph;
  }
}

七)delay.h

#ifndef __DELAY_H
#define __DELAY_H 			   
#include <sys.h>	  
	 
void delay_init(u8 SYSCLK);
void delay_ms(u16 nms);
void delay_us(u32 nus);

#endif

http://www.kler.cn/a/488814.html

相关文章:

  • C++类的引入
  • 【数据库】一、数据库系统概述
  • 大模型技术与应用:从幻觉到蒸馏,全面解析
  • Erlang语言的网络编程
  • uniapp:钉钉小程序需要录音权限及调用录音
  • Linux 下信号的保存和处理
  • Win10本地部署大语言模型ChatGLM2-6B
  • [豆包MarCode AI 刷题] 算法题解 Java 青训入营考核 五题打卡第三天
  • 网络安全:守护数字世界的防线
  • 【react-pdf】实现在线pdf加载——翻页加载和下拉滚动加载
  • Vue.js组件开发-实现滚动加载下一页
  • HOW - Form 表单 label 和 wrapper 对齐场景
  • 统信桌面常用运维命令
  • 【华为OD-E卷 - 服务失效判断 100分(python、java、c++、js、c)】
  • LeetCode 747. 至少是其他数字两倍的最大数
  • C++—14、C++ 中的指针最基础的原理
  • React 元素渲染
  • 苍穹外卖的微信支付和接单和催单提醒
  • 青少年编程与数学 02-006 前端开发框架VUE 16课题、组件基础
  • 初学stm32 --- ADC多通道采集
  • 鸿蒙原生应用如何才能拉起系统浏览器?
  • Linux 命令与日志查看实用指南
  • 详解Sonar与Jenkins 的集成使用!
  • 【C++】Muduo库
  • vivado 时钟指南
  • .gitignore记录