(9)Proteus 8.9上的STM32仿真系列(HAL/CubeMaxIDE)---IIC/I2C实验

(9)Proteus 8.9上的STM32仿真系列(HAL/CubeMaxIDE)—IIC/I2C实验

实验设计: Proteus上的stm32硬件IIC测试失败,本处采用模拟IIC。控制PCF8574电平,并读取其状态从串口1输出。
一、Proteus原理图(芯片stm32f103r6tx)
1.可以不放逻辑分析仪,COMPIM点开波特率设置为9600。
在这里插入图片描述
二、CubemaxIDE配置
1.时钟和第一节相同,直接HCLK 8Mhz。
2.使能uart1,设置9600波特率
在这里插入图片描述
3.配置PB0,PB1,后面会重新设置输入输出模式,这里简单打开就好。在这里插入图片描述
4.generate code,需要添加6个文件,delay.c/delay.h如上一节,需新添加Soft_IIC.c/Soft_IIC.h和PCF8574.C/PCF8574.h。后两个文件源代码如下。
目录结构:
在这里插入图片描述
Soft_IIC.h

#ifndef __SOFT_IIC_H
#define   __SOFT_IIC_H

#include "delay.h"

/* 高低电平 */
#define HIGH	1
#define LOW		0

/* IO方向设置 */
#define SDA_IN()  {GPIOB->CRL&=~(15<<(0*2));GPIOB->CRL|=4<<(0*2);}		//PB0浮空输入模式
#define SDA_OUT() {GPIOB->CRL&=~(3<<(0*2));GPIOB->CRL|=1<<(0*2);} 	//PB0输出模式10Mhz
/* IO操作 */
#define IIC_SCL(n)  (n?HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET)) //SCL
#define IIC_SDA(n)  (n?HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET)) //SDA
#define READ_SDA    HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)					//输入SDA

/* IIC所有操作函数 */
void IIC_Init(void);										//IIC初始化
void IIC_Start(void);										//产生IIC起始信号
void IIC_Stop(void);										//产生IIC停止信号
uint8_t   IIC_Wait_Ack(void);									//等待ACK信号到来
void IIC_Ack(void);											//产生ACK应答
void IIC_NAck(void);										//不产生ACK应答
void IIC_Send_Byte(uint8_t txd);									//IIC发送一个字节
uint8_t   IIC_Read_Byte(unsigned char ack);						//IIC读取一个字节

#endif

Soft_IIC.c

#include "Soft_IIC.h"

/***************************************************************
 @Function			void IIC_Init(void)
 @Description		IIC初始化
 @Input				void
 @Return			void
***************************************************************/
void IIC_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	  __HAL_RCC_GPIOD_CLK_ENABLE();
	  __HAL_RCC_GPIOB_CLK_ENABLE();
	  __HAL_RCC_GPIOA_CLK_ENABLE();									//使能GPIOB时钟

	/* PB0,1初始化设置 */
	  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
	  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	  GPIO_InitStruct.Pull = GPIO_PULLUP;
	  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	  IIC_SDA(HIGH);
	  IIC_SCL(HIGH);
}

/***************************************************************
 @Function			void IIC_Start(void)
 @Description		产生IIC起始信号
					SCL : HIGH
					SDA : HIGH -> LOW
 @Input				void
 @Return			void
***************************************************************/
void IIC_Start(void)
{
	SDA_OUT();														//sda线输出
	IIC_SDA(HIGH);
	IIC_SCL(HIGH);
	delay_us(4);
	IIC_SDA(LOW);		//START : when CLK is high,DATA change form high to low
	delay_us(4);
	IIC_SCL(LOW);													//钳住I2C总线,准备发送或接收数据
}

/***************************************************************
 @Function			void IIC_Stop(void)
 @Description		产生IIC停止信号
					SCL : HIGH
					SDA : LOW -> HIGH
 @Input				void
 @Return			void
***************************************************************/
void IIC_Stop(void)
{
	SDA_OUT();														//sda线输出
	IIC_SDA(LOW);
	IIC_SCL(HIGH);
	delay_us(4);
	IIC_SDA(HIGH);		//STOP : when CLK is high,DATA change form low to high
	delay_us(4);
}

/***************************************************************
 @Function			uint8_t IIC_Wait_Ack(void)
 @Description		等待ACK信号到来
 @Input				void
 @Return			1 : 接收应答失败
					0 : 接收应答成功
***************************************************************/
uint8_t IIC_Wait_Ack(void)
{
	uint8_t ucErrTime = 0;

	SDA_IN();														//SDA设置为输入
	IIC_SDA(HIGH);delay_us(1);
	IIC_SCL(HIGH);delay_us(1);
	while (READ_SDA) {
		ucErrTime++;
		if (ucErrTime > 250) {
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL(LOW);													//时钟输出0
	return 0;
}

/***************************************************************
 @Function			void IIC_Ack(void)
 @Description		产生ACK应答
 @Input				void
 @Return			void
***************************************************************/
void IIC_Ack(void)
{
	SDA_OUT();														//sda线输出
	IIC_SCL(LOW);
	IIC_SDA(LOW);
	delay_us(2);
	IIC_SCL(HIGH);
	delay_us(2);
	IIC_SCL(LOW);
}

/***************************************************************
 @Function			void IIC_NAck(void)
 @Description		不产生ACK应答
 @Input				void
 @Return			void
***************************************************************/
void IIC_NAck(void)
{
	SDA_OUT();														//sda线输出
	IIC_SCL(LOW);
	IIC_SDA(HIGH);
	delay_us(2);
	IIC_SCL(HIGH);
	delay_us(2);
	IIC_SCL(LOW);
}

/***************************************************************
 @Function			void IIC_Send_Byte(uint8_t txd)
 @Description		IIC发送一个字节
 @Input				txd : 发送数据
 @Return			void
***************************************************************/
void IIC_Send_Byte(uint8_t txd)
{
	uint8_t t;

	SDA_OUT();														//sda线输出
	IIC_SCL(LOW);													//拉低时钟开始数据传输
	for (t = 0; t < 8; t++)
	{
		IIC_SDA((txd & 0x80) >> 7);
		txd <<= 1;
		delay_us(2);
		IIC_SCL(HIGH);
		delay_us(2);
		IIC_SCL(LOW);
		delay_us(2);
	}
}

/***************************************************************
 @Function			uint8_t IIC_Read_Byte(unsigned char ack)
 @Description		读1个字节,ack=1时,发送ACK,ack=0,发送nACK
 @Input				ack
 @Return			所读数据
***************************************************************/
uint8_t IIC_Read_Byte(unsigned char ack)
{
	unsigned char i, receive = 0;

	SDA_IN();														//SDA设置为输入
	for (i = 0; i < 8; i++)
	{
		IIC_SCL(LOW);
        delay_us(2);
		IIC_SCL(HIGH);
        receive <<= 1;
        if (READ_SDA) receive++;
		delay_us(1);
	}
	if (!ack)
		IIC_NAck();													//发送nACK
	else
		IIC_Ack();													//发送ACK

	return receive;
}

PCF8574.h

#ifndef __PCF8574_H
#define __PCF8574_H
#include "delay.h"
#include "Soft_IIC.h"

//#define PCF8574_INT  PBin(12) //PCF8574 INT脚

#define PCF8574_ADDR 	0X40	//PCF8574地址为  0 1 0 0 A2 A1 A0 R/W

uint8_t PCF8574_Init(void);
uint8_t PCF8574_ReadOneByte(void);
void PCF8574_WriteOneByte(uint8_t DataToWrite);
void PCF8574_WriteBit(uint8_t bit,uint8_t sta);
uint8_t PCF8574_ReadBit(uint8_t bit);

#endif

PCF8574.c

#include "PCF8574.h"
//读取PCF8574的8位IO值
//返回值:读到的数据
uint8_t PCF8574_ReadOneByte(void)
{
	uint8_t temp=0;
    IIC_Start();
	IIC_Send_Byte(PCF8574_ADDR|0X01);   //进入接收模式
	IIC_Wait_Ack();
    temp=IIC_Read_Byte(0);
    IIC_Stop();							//产生一个停止条件
	return temp;
}
//向PCF8574写入8位IO值
//DataToWrite:要写入的数据
void PCF8574_WriteOneByte(uint8_t DataToWrite)
{
    IIC_Start();
    IIC_Send_Byte(PCF8574_ADDR|0X00);   //发送器件地址0X40,写数据
	IIC_Wait_Ack();
	IIC_Send_Byte(DataToWrite);    	 	//发送字节
	IIC_Wait_Ack();
    IIC_Stop();							//产生一个停止条件
	delay_ms(10);
}

//设置PCF8574某个IO的高低电平
//bit:要设置的IO编号,0~7
//sta:IO的状态;0或1
void PCF8574_WriteBit(uint8_t bit,uint8_t sta)
{
    uint8_t data;
    data=PCF8574_ReadOneByte(); //先读出原来的设置
    if(sta==0)data&=~(1<<bit);
    else data|=1<<bit;
    PCF8574_WriteOneByte(data); //写入新的数据
}

//读取PCF8574的某个IO的值
//bit:要读取的IO编号,0~7
//返回值:此IO的值,0或1
uint8_t PCF8574_ReadBit(uint8_t bit)
{
    uint8_t data;
    data=PCF8574_ReadOneByte(); //先读取这个8位IO的值
    if(data&(1<<bit))return 1;
    else return 0;
}

5.main.c中添加代码
(1)包含头文件

#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "delay.h"
#include "Soft_IIC.h"
#include "PCF8574.h"
/* USER CODE END Includes */

(2)声明一个uint8_t 记录PCF8574状态

/* USER CODE BEGIN PV */
uint8_t IIC_READ;
/* USER CODE END PV */

(3)主函数

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  delay_init(8);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  PCF8574_WriteOneByte(0xf0);						//置PCF8574高四位高电平
	  IIC_READ=PCF8574_ReadOneByte();					//读取PCF8574状态
	  HAL_UART_Transmit(&huart1, &IIC_READ, 1, 0xff);	//将PCF8574状态从uart1输出
	  delay_ms(500);									//延时500ms
	  //翻转电平,重复上述操作
	  PCF8574_WriteOneByte(0x0f);
	  IIC_READ=PCF8574_ReadOneByte();
	  HAL_UART_Transmit(&huart1, &IIC_READ, 1, 0xff);
	  delay_ms(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

6.设置导出hex文件,buildall
三、实验结果
(1)电平翻转及uart1输出
在这里插入图片描述
(2)逻辑分析仪捕获的电平信号(建议COMPIM和逻辑分析仪不要同时仿真,要不然速度慢,电脑性能好的同志可以试试)
读取PCF8574信号(0x41 0xf0)
在这里插入图片描述
写入PCF8574信号(0x40 0xf0)
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值