一、基本概念
二、特性说明
三、内存结构
四、器件地址
五、指令描述
/***********************************************************************************
* @file main.c
* @author [email protected]
* @version V1
* @date 2024-11-13
* @brief AT24C02存储IC的指令设计
***********************************************************************************/
#include "stm32f4xx.h"
#include <stdio.h>
#include <stdbool.h>
//使用IO口来模拟IIC时序,从而控制从器件
#define IIC_SDA(n) (n) ? GPIO_SetBits(GPIOB,GPIO_Pin_9) : GPIO_ResetBits(GPIOB,GPIO_Pin_9)
#define IIC_SCL(n) (n) ? GPIO_SetBits(GPIOB,GPIO_Pin_8) : GPIO_ResetBits(GPIOB,GPIO_Pin_8)
#define IIC_READ GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)
//延时微秒 注意:24bit计数器 不能798915us
void delay_us(u32 nus)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = nus*21 - 1; // 设置重载值
SysTick->VAL = 0; // 清除计数值
SysTick->CTRL = 1; // 开启定时器 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待时间到达
SysTick->CTRL = 0; // 关闭定时器
}
//延时毫秒 注意:24bit计数器 不能798ms
void delay_ms(u32 nms)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = nms*21000 - 1; // 设置重载值
SysTick->VAL = 0; // 清除计数值
SysTick->CTRL = 1; // 开启定时器 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待时间到达
SysTick->CTRL = 0; // 关闭定时器
}
//串口1的初始化
void USART1_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//1.打开GPIO端口 PA9 PA10
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//2.打开串口时钟 USART1 -- APB2
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//3.选择引脚的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10 , GPIO_AF_USART1);
//4.配置GPIO引脚参数并初始化
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //输出速度
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉电阻
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9; //引脚编号
GPIO_Init(GPIOA, &GPIO_InitStructure);
//5.配置USART1的参数并初始化
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //检验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure);
//6.配置中断参数并初始化
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //中断通道编号
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打开中断通道
NVIC_Init(&NVIC_InitStructure);
//7.选择中断源 接收到数据则触发中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//8.打开USART1
USART_Cmd(USART1, ENABLE);
}
//发送字符串的函数
void USART1_SendString(char *str)
{
//循环发送字符
while( *str != '\0' )
{
USART_SendData(USART1,*str++);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET ); //等待发送数据寄存器为空 表示发送完成
}
}
//IIC时序: 起始信号 + 发送字节 + 从机应答 + 读取字节 + 主机应答 + 停止信号
//IIC的初始化
void IIC_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //输出速度
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉电阻
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //引脚编号
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //引脚编号
GPIO_Init(GPIOB, &GPIO_InitStructure);
//确保SDA和SCL都处于空闲状态
IIC_SDA(1);
IIC_SCL(1);
}
//SDA设置为输出模式
static void IIC_SDASetOutputMode(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //输出速度
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉电阻
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //引脚编号
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//SDA设置为输入模式
static void IIC_SDASetInputMode(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //输入模式
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉电阻
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //引脚编号
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//IIC的开始信号
void IIC_Start(void)
{
//1.SDA引脚设置为输出模式
IIC_SDASetOutputMode();
//2.确保SDA和SCL为空闲状态 高电平
IIC_SDA(1);
IIC_SCL(1);
delay_us(5);
//3.在SCL高电平期间,把SDA电平拉低
IIC_SDA(0);
delay_us(5);
//4.把SCL时钟线的电平拉低
IIC_SCL(0);
delay_us(5);
}
//IIC发送字节
void IIC_SendByte(uint8_t data)
{
uint8_t i = 0;
//1.SDA引脚设置为输出模式
IIC_SDASetOutputMode();
//2.把SCL时钟线电平拉低
IIC_SCL(0);
delay_us(5);
//3.循环发送8bit数据
for(i=0;i<8;i++)
{
//4.分析待发送数据的最高位 MSB
if( data & 0x80 )
IIC_SDA(1);
else
IIC_SDA(0);
data <<= 1; //数据左移1bit
delay_us(5);
//5.把SCL时钟线的电平拉高,此时从机可以读取
IIC_SCL(1);
delay_us(5);
//6.把SCL时钟线的电平拉低,此时主机可以准备
IIC_SCL(0);
delay_us(5);
}
}
//IIC的等待从器件应答
bool IIC_WaitSlaveAck(void)
{
//1.设置SDA数据线为输入模式
IIC_SDASetInputMode();
//2.把SCL时钟线的电平拉低,此时从机可以准备
IIC_SCL(0);
delay_us(5);
//3.把SCL时钟线的电平拉高,此时从机可以读取
IIC_SCL(1);
delay_us(5);
//4.主器件读取SDA数据线的电平状态
if( IIC_READ )
return false;
else
return true;
}
//IIC读取字节
uint8_t IIC_ReadByte(void)
{
uint8_t data = 0;
uint8_t i = 0;
//1.设置SDA数据线为输入模式
IIC_SDASetInputMode();
//2.把SCL时钟线的电平拉低,此时从机可以准备
IIC_SCL(0);
delay_us(5);
//3.循环读取8bit数据并存储在变量
for(i=0;i<8;i++)
{
//4.把SCL时钟线的电平拉高,此时主机可以读取
IIC_SCL(1);
delay_us(5);
//5.读取SDA数据线的电平状态 MSB
data <<= 1;
data |= IIC_READ;
//6.把SCL时钟线的电平拉低,此时从机可以准备
IIC_SCL(0);
delay_us(5);
}
return data;
}
//IIC主机发送应答
void IIC_MasterSendAck(uint8_t ack)
{
//1.SDA引脚设置为输出模式
IIC_SDASetOutputMode();
//2.把SCL时钟线的电平拉低,此时主机可以准备
IIC_SCL(0);
delay_us(5);
//3.主机进行应答
if( ack )
IIC_SDA(1); //表示不应答
else
IIC_SDA(0); //表示应答了
delay_us(5);
//4.把SCL时钟线的电平拉高,此时从机可以读取
IIC_SCL(1);
delay_us(5);
}
//IIC发送停止信号
void IIC_Stop(void)
{
//1.SDA引脚设置为输出模式
IIC_SDASetOutputMode();
//2.确保SDA和SCL都输出低电平
IIC_SDA(0);
IIC_SCL(0);
delay_us(5);
//3.把SCL时钟线的电平拉高
IIC_SCL(1);
delay_us(5);
//4.把SDA时钟线的电平拉高
IIC_SDA(1);
delay_us(5);
}
//AT24C02初始化
void AT24C02_Config(void)
{
IIC_Config();
}
//AT24C02字节写入指令
void AT24C02_ByteWrite(uint8_t Addr,uint8_t Data)
{
//1.主机发送开始信号
IIC_Start();
//2.主机发送器件地址
IIC_SendByte(0xA0);
//3.等待从机应答
while( IIC_WaitSlaveAck() == false );
//4.主机发送存储地址
IIC_SendByte(Addr);
//5.等待从机应答
while( IIC_WaitSlaveAck() == false );
//6.主机发送存储内容
IIC_SendByte(Data);
//7.等待从机应答
while( IIC_WaitSlaveAck() == false );
//8.主机发送停止信号
IIC_Stop();
}
//程序入口
int main()
{
//1.硬件初始化
USART1_Config(9600);
AT24C02_Config();
while(1)
{
}
}
void USART1_IRQHandler(void)
{
uint8_t data = 0;
//判断中断是否触发
if( USART_GetITStatus(USART1, USART_IT_RXNE) == SET )
{
data = USART_ReceiveData(USART1); //一次只能接收1个字节
USART_SendData(USART1,data); //通过USART1发送1字节
}
}
标签:Pin,USART,学习,InitStructure,AT24C02,IIC,GPIO,USART1,关于
From: https://www.cnblogs.com/hhail08/p/18544669