乐趣区

关于stm:基于STM32F1单片机的通信方式

通用同步异步收发器(USART)

USART 介绍

  • 全双工的异步通信。
  • 接口通过三个引脚与其余设施连贯在一起(接管 RX、发送 TX、时钟输入 CK)(任何 USART 双向通信至多须要 RX 和 TX)
  • 发送方为同步传输提供时钟。
  • 发送和接管由一共用的波特率发生器驱动,当发送器和接收器的使能位别离置位时,别离为其产生时钟。
  • 波特率

    • 应用分数波特率发生器零碎
    • 发送和接管共用的可编程波特率,最高达 4.5Mbits/s
    • 12 位整数和 4 位小数的示意办法。
    • 只有 USART1 应用 PCLK2(即 APB2 最高 72MHz)。其它 USART 应用 PCLK1(即 APB1 最高 36MHz)。
  • 可编程数据字长度(8 位或 9 位)(8 数据 + n 进行位 / 9 数据 + n 进行位)(数据位最初一个可能是奇偶校验位)(数据最低无效位在前)
  • 可配置的进行位 - 反对 1 或 2 个进行位。
  • 发送和接收数据流程:(数据寄存器 USART_DR 蕴含发送寄存器 TDR 和接管寄存器 RDR)

    • 发送数据:零碎进行写操作将数据写入发送寄存器 TDR,而后 TDR 将数据移送到发送移位寄存器中,再由发送移位寄存器送入编解码模块中编码后从 TX 输入。
    • 接收数据;数据从 RX 进入,先到编解码模块中解码后送入接管移位寄存器,而后再到接管寄存器 RDR 中供零碎进行读操作。
  • 当发送使能位 (TE) 被设置时,发送移位寄存器中的数据在 TX 脚上输入,相应的时钟脉冲在 CK 脚上输入。
  • 留神:在数据传输期间不能复位 TE 位,否则将毁坏 TX 脚上的数据,因为波特率计数器进行计数。正在传输的以后数据将失落。

分数波特率的计算

  • 波特率 = PCK /(16*USARTDIV)(USARTDIV 是波特比率寄存器中的值换算失去,即分频系数)
  • 已知 USARTDIV = 25.62;求波特比率寄存器 USART_BRR 该写入的值。

    • DIV_Fraction = 16*0.62 = 9.92。最靠近的整数是:10 = 0xA
    • DIV_Mantissa = 取整(25.620) = 25 = 0x019。(整数局部是 12 位所以是 0x019,写 0x19 也行,这里是为了好分别)、
    • 所以 USART_BRR = 0x019A(写作 0x19A 也行)

USART 的中断请求

  • USART 的各种中断事件被连贯到同一个中断向量
  • 以下各种状况会触发中断:(如果设置了对应的使能管制位,这些事件就能够产生各自的中断)

    • 发送期间:发送实现、革除发送、发送数据寄存器为空。
    • 接管期间:闲暇总线检测、溢出谬误、接收数据寄存器非空、校验谬误、LIN 断开符号检测、乐音标记 (仅在多缓冲器通信) 和帧谬误(仅在多缓冲器通信)。

USART 寄存器

状态寄存器(USART_SR)

  • 复位值:0x00C0
  • TXE: 发送寄存器 DTR 是否为空标记位。

    • 当 TDR 寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。
    • 如果管制寄存器 USART_CR1 中的 TXEIE 为 1,则产生中断。
    • 对数据寄存器 USART_DR 的写操作,硬件会将该位清零。
    • 1:数据曾经被转移到移位寄存器。
  • TC:发送实现标记位。

    • 当一帧数据发送实现后,并且 TXE= 1 时,该位被硬件置一。
    • 如果管制寄存器 USART_CR1 中的 TXEIE 为 1,则产生中断。
    • 由软件序列革除该位(先读 USART_SR,而后写入 USART_DR)
    • 1:发送实现。
  • RXNE:查看接管移位寄存器是否为空标记位。

    • 当接管移位寄存器中的数据被转移到接收数据寄存器 RDR 中时,该位被硬件置位(接管移位寄存器中为空)
    • 如果管制寄存器 USART_CR1 中的 RXNEIE 为 1,则产生中断。
    • 对数据寄存器 USART_DR 的读操作能够将该位清零。
    • 1:收到数据,能够读出。
  • IDLE:监测到总线闲暇标记位。

    • 当检测到总线闲暇时,该位被硬件置位。
    • 如果 USART_CR1 中的 IDLEIE 为 1,则产生中断。
    • 由软件序列革除该位(先读 USART_SR,而后读 USART_DR)。
    • 1:检测到闲暇总线。

数据寄存器(USART_DR)

  • 复位值:不确定
  • DR:数据值,蕴含了发送或接管的数据。

波特比率寄存器(USART_BRR)

  • 复位值:0x0000
  • DIV_Mantissa:USARTDIV 的整数局部
  • DIV_Fraction:USARTDIV 的小数局部

管制寄存器 1(USART_CR1)

  • 复位值:0x0000
  • UE:USART 使能位。该位由软件设置和清零。(0:USART 分频器和输入被禁止)
  • M:设置传输字长,由软件对其设置和清零(0:8 个数据位。1:9 个数据位)
  • PCE:测验管制使能(1:使能校验管制)
  • PS:校验抉择(0:偶校验)
  • PEIE:PE 中断使能(1:当 USART_SR 中的 TXE 为 1 时,产生 USART 中断)
  • TCIE:发送实现中断使能(1:当 USART_SR 中的 TC 为 1 时,产生 USART 中断)
  • RXNEIE:接管移位寄存器为空的中断使能(1:当 USART_SR 中的 ORE 或者 RXNE 为 1 时,产生 USART 中断)
  • IDLEIE:总线闲暇 IDLE 中断使能(该位由软件设置或革除)(1:当 USART_SR 中的 IDLE 为 1 时,产生 USART 中断)
  • TE:发送使能(1:使能发送)
  • RE:接管使能(1:使能接管,并开始搜查 RX 引脚上的起始位)

管制寄存器 2(USART_CR2)

  • 复位值:0x0000
  • STOP:进行位(UART4 和 UART5 不能用 0.5 进行位和 1.5 进行位)

    • 00:1 个进行位。
    • 01:0.5 个进行位。
    • 10:2 个进行位。
    • 11:1.5 个进行位
  • CLKEN:时钟使能(0:禁止 CK 引脚)

代码示例

  • USART 初始化设置

/*******************************************************************************
* 函 数 名         : USART1_Init
* 函数性能           : USART1 初始化函数
* 输    入         : bound: 波特率
* 输    出         : 无
*******************************************************************************/ 
void USART1_Init(u32 bound)
{
   //GPIO 端口设置
    GPIO_InitTypeDef GPIO_InitStructure;    // 申明 GPIO 对象
    USART_InitTypeDef USART_InitStructure;    // 申明串口对象
    NVIC_InitTypeDef NVIC_InitStructure;    // 申明嵌套断的对象
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
 
    
    /*  配置 GPIO 的模式和 IO 口 */
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX               // 串口输入 PA9
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;        // 复用推挽输入
    GPIO_Init(GPIOA,&GPIO_InitStructure);  /* 初始化串口输入 PA9*/
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX             // 串口输出 PA10
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;          // 模仿输出
    GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输出 PA10*/
    

   //USART1 初始化设置
    USART_InitStructure.USART_BaudRate = bound;// 波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 字长为 8 位数据格式
    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); // 初始化串口 1
    
    USART_Cmd(USART1, ENABLE);  // 使能串口 1 
    
    USART_ClearFlag(USART1, USART_FLAG_TC);  // 革除串口的挂起标记
        
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 开启相干中断

    //Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;        // 串口 1 中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; // 抢占优先级 3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;        // 子优先级 3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ 通道使能
    NVIC_Init(&NVIC_InitStructure);    // 依据指定的参数初始化 VIC 寄存器、}

  • 串口的中断函数


/*******************************************************************************
* 函 数 名         : USART1_IRQHandler
* 函数性能           : USART1 中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/ 
void USART1_IRQHandler(void)                    // 串口 1 中断服务程序
{
    u8 r;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  // 接管中断
    {r =USART_ReceiveData(USART1);//(USART1->DR);    // 读取接管到的数据
        USART_SendData(USART1,r);          //    将接管到的数据再发送回去
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
    } 
    USART_ClearFlag(USART1,USART_FLAG_TC);
} 

I2C 通信之 EEPROM

I2C 特点

  • 遵循着与 51 单片机雷同的 I2C 协定。
  • 接口通过数据引脚 (SDA) 和时钟引脚 (SCL) 连贯到 I2C 总线(数据引脚 SDA 用于数据传输,时钟引脚 SCL 用于收发数据的同步)
  • I2C 模块接管和发送数据,并将数据从串行转换成并行,或并行转换成串行。
  • I2C 主设施性能:

    • 产生时钟。
    • 产生起始和进行信号。
  • I2C 从设施性能:

    • 可编程的 I2C 地址检测。
    • 可响应 2 个从地址的双地址能力。
    • 进行位检测。
  • 反对不同的通信速度:

    • 规范速度(高达 100 kHz)
    • 疾速(高达 400 kHz)
  • 状态标记:

    • 发送器 / 接收器模式标记。
    • 字节发送完结标记。
    • I2C 总线忙标记。
  • 谬误标记:

    • 主模式时的仲裁失落。
    • 地址 / 数据传输后的应答 (ACK) 谬误。
    • 检测到错位的起始或进行条件。
    • 禁止拉长时钟性能时的上溢或下溢。
  • 领有 2 个中断向量:

    • 1 个中断用于地址 / 数据通讯胜利。
    • 1 个中断用于谬误。

    I2C 通信流程

    1. 主机发送 I2C 起始信号(通过 SDA 线)并产生时钟信号,通知从机要开始传输信号了(所有从机都会收到这个起始信号)
    2. 此时主机会播送从机地址(每个从机地址惟一)(跟在起始条件之后的 1 个或 2 个字节就是地址),匹配到后与之对应的从机地址会给出一个应答信号。
    3. 在发送从地址时,设施也会告知从设施是发送数据还是接收数据(TRA 位标记主设施是在接收器模式还是发送器模式)
    4. 在 7 位地址模式时:

    • 进入发送数据模式:主设施发送从地址时最低位为’0’。
    • 进入接收数据模式:主设施发送从地址时最低位为’1’。

    5. 在 10 位地址模式时:

    • 进入发送数据模式:主设施先送头字节(11110xx0),而后送最低位为’0’的从地址(这里 xx 代表 10 位地址中的最高 2 位)
    • 进入接收数据模式:主设施先送头字节(11110xx0),而后送最低位为’1’的从地址。而后再从新发送一个开始条件,前面跟着头字节(11110xx1)(这里 xx 代表 10 位地址中的最高 2 位)

    6. 从器件地址约定:

    • 8 位从器件地址的高 4 位固定为 1010,接下来的 3 位示意要读写存储器的地址,最初一位为读写管制位(1 示意读)

    7. 如果从机许可的话就能够进行通信了。
    8. 在进行通信时,主机会发送进行信号,通知从机到此结束。

I2C 模式抉择

  • 四种运行模式:(该模块默认地工作于从模式)

    • 从发送器模式
    • 从接收器模式
    • 主发送器模式
    • 主接收器模式
    • 留神:接口在生成起始条件后主动地从从模式切换到主模式;当仲裁失落或产生进行信号时,则从主模式切换到从模式。
  • 数据传输流程:串行数据传输总是以起始条件开始并以进行条件完结,并且在一个字节传输的 8 个时钟后的第九个时钟,接收器必须回应一个应答信号 (ACK) 给发送器。当通过 START 位在总线上产生了起始条件,设施就进入了主模式。(设施默认从模式)

I2C 中断请求

  • SB、ADDR、ADD10、STOPF、BTF、RxNE 和 TxE 通过逻辑或应用同一个中断通道(it_event 事件中断)
  • BERR、ARLO、AF、OVR、PECERR、TIMEOUT 和 SMBALERT 通过逻辑或应用同一个中断通道(it_error 谬误中断)

I2C 寄存器形容

管制寄存器 1 (I2C_CR1)

  • 复位值:0x0000
  • SWRST:软件复位

    • 当被置位时,I2C 处于复位状态。在复位该位前确信 I2C 的引脚被开释,总线是空的
    • 0:I2C 模块不处于复位状态
    • 1: I2C 模块处于复位状态
  • ACK:应答使能

    • 软件能够设置或革除该位,或当 PE= 0 时,由硬件革除
    • 0:无应答返回
    • 1:在接管到一个字节后返回一个应答(匹配的地址或数据)
  • STOP:进行条件产生

    • 软件能够设置或革除该位
    • 当检测到进行条件时,由硬件革除
    • 当检测到超时谬误时,硬件将其置位
    • 在主模式下:1:在以后字节传输或在以后起始条件收回后产生进行条件
    • 在从模式下:1:在以后字节传输或开释 SCL 和 SDA 线后产生进行条件
    • 留神:当设置了 STOP、START 或 PEC 位,在硬件革除这个位之前,软件不要执行任何对 I2C_CR1 的写操作;否则有可能会第 2 次设置 STOP、START 或 PEC 位
  • START:起始条件产生

    • 软件能够设置或革除该位
    • 当起始条件收回后或 PE= 0 时,由硬件革除
    • 在主模式下:1:反复产生起始条件
    • 在从模式下:1:当总线闲暇时,产生起始条件
  • ENGC:播送呼叫使能(1:容许播送呼叫. 以应答响应地址 00h)
  • ENPEC:PEC 使能(ENPEC:PEC 使能)
  • ENARP:ARP 使能

    • 1:使能 ARP
    • 如果 SMBTYPE=0,应用 SMBus 设施的默认地址
    • 如果 SMBTYPE=1,应用 SMBus 的主地址
  • SMBTYPE:SMBUS 类型(0:SMBus 设施;1:SMBUS 主机)
  • SMBUS:SMBUS 模式(0:I2C 模式;1:SMBUS 模式)
  • PE:I2C 模块使能(1:启用 I2C 模块,依据 SMBUS 位的设置,相应的 I / O 口需配置为复用性能)

管制寄存器 2(I2C_CR2)

  • 复位值:0x0000
  • LAST: DMA 最初一次传输(1:下一次 DMA 的 EOT 是最初的传输)
  • DMAEN:DMA 申请使能(1:当 TxE= 1 或 RxNE = 1 时,容许 DMA 申请)
  • ITBUFEN:缓冲器中断使能(1:当 TxE= 1 或 RxNE= 1 时,产生事件中断,不论 DMAEN 是何种状态)
  • ITEVTEN:事件中断使能(1:容许事件中断)
  • ITERREN:出错中断使能(1:容许出错中断)
  • FREQ[5:0]:I2C 模块时钟频率(必须设置正确的输出时钟频率产生正确的时序,范畴在 2~36MHz 之间)

    • 000000:禁用
    • 000001:禁用
    • 000010:2MHz
    • …….
    • 100100:36MHz
    • 大于 100100:禁用

本身地址寄存器 1(I2C_OAR1)

  • 复位值:0x0000
  • ADDMODE:寻址模式(在从模式中)

    • 0:7 位从地址(不响应 10 位地址)
    • 1:10 位从地址(不响应 7 位地址)
  • 位 14:必须始终由软件放弃为 1。
  • ADD[9:8]:接口地址

    • 7 位地址模式时不必关怀
    • 10 位地址模式时为地址的 9~8 位
  • ADD[7:1]:接口地址(地址的 7~1 位)
  • ADD0:接口地址

    • 7 位地址模式时不必关怀
    • 10 位地址模式时为地址第 0 位

数据寄存器(I2C_DR)

  • 复位值:0x0000
  • DR:8 位数据寄存器

    • 用于寄存接管到的数据或搁置用于发送到总线的数据

状态寄存器 1(I2C_SR1)

  • 复位值:0x0000
  • SMBALERT:SMBus 揭示
  • TIMEOUT:超时或 Tlow 谬误
  • PECERR:在接管时产生 PEC 谬误
  • OVR:过载 / 欠载
  • AF:应答失败
  • ARLO:仲裁失落(主模式)
  • BERR:总线出错
  • TxE:数据寄存器为空(发送时)
  • RxNE:数据寄存器非空(接管时)
  • STOPF:进行条件检测位(从模式)
  • ADD10:10 位头序列已发送(主模式)
  • BTF:字节发送完结
  • ADDR:地址已被发送(主模式)/ 地址匹配(从模式)
  • SB:是否发送起始条件(主模式)

状态寄存器 2 (I2C_SR2)

  • 复位值:0x0000
  • PEC[7:0]:数据包出错检测
  • DUALF:双标记(从模式)
  • SMBHOST: SMBus 主机头系列(从模式)
  • SMBDEFAULT:SMBus 设施默认地址(从模式)
  • GENCALL:播送呼叫地址(从模式)
  • TRA:数据是否发送 / 接管
  • BUSY:总线忙
  • MSL:主从模式

时钟管制寄存器(I2C_CCR)

  • 复位值:0x0000
  • 留神:

    • 要求 FPCLK1 该当是 10 MHz 的整数倍,这样能够正确地产生 400KHz 的疾速时钟
    • CCR 寄存器只有在敞开 I2C 时 (PE=0) 能力设置
  • F/S:I2C 主模式选项
  • DUTY:疾速模式时的占空比
  • CCR:疾速 / 规范模式下的时钟管制分频系数(主模式)

代码示例

  • I2C 代码
#include "iic.h"
#include "SysTick.h"

//IO 操作函数     
#define IIC_SCL    PBout(10) //SCL
#define IIC_SDA    PBout(11) //SDA     
#define READ_SDA   PBin(11)  // 输出 SDA


/*******************************************************************************
* 函 数 名         : IIC_Init
* 函数性能           : IIC 初始化
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void IIC_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(IIC_SCL_PORT_RCC|IIC_SDA_PORT_RCC,ENABLE);
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;         // 指定 PB10 作为 SCL 线
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB,&GPIO_InitStructure);                // 初始化 I / O 口
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;            // 指定 PB11 为 SDA 线
    GPIO_Init(GPIOB,&GPIO_InitStructure);
    
    IIC_SCL=1;
    IIC_SDA=1;    
}

/*******************************************************************************
* 函 数 名         : SDA_OUT
* 函数性能           : SDA 输入配置       
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void SDA_OUT(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
}

/*******************************************************************************
* 函 数 名         : SDA_IN
* 函数性能           : SDA 输出配置       
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void SDA_IN(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
}

/*******************************************************************************
* 函 数 名         : IIC_Start
* 函数性能           : 产生 IIC 起始信号   
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void IIC_Start(void)
{SDA_OUT();     //SDA 线输入
    IIC_SDA=1;     //SDA 线拉高       
    IIC_SCL=1;        //SCL 线拉高
    delay_us(5);
     IIC_SDA=0;    // 当 CLK 值为高时,SDA 由高变低示意起始信号
    delay_us(6);
    IIC_SCL=0;    // 钳住 I2C 总线,筹备发送或接收数据 
}    

/*******************************************************************************
* 函 数 名         : IIC_Stop
* 函数性能           : 产生 IIC 进行信号   
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void IIC_Stop(void)
{SDA_OUT();    //sda 线输入
    IIC_SCL=0;
    IIC_SDA=0;    
     IIC_SCL=1; 
    delay_us(6); 
    IIC_SDA=1;    // 当 CLK 值为高时,SDDA 由低变高示意进行信号
    delay_us(6);                                   
}

/*******************************************************************************
* 函 数 名         : IIC_Wait_Ack
* 函数性能           : 期待应答信号到来   
* 输    入         : 无
* 输    出         : 1,接管应答失败
                     0,接管应答胜利
*******************************************************************************/
u8 IIC_Wait_Ack(void)
{
    u8 tempTime=0;
    
    IIC_SDA=1;
    delay_us(1);
    SDA_IN();      //SDA 设置为输出         
    IIC_SCL=1;
    delay_us(1);     
    while(READ_SDA)
    {
        tempTime++;
        if(tempTime>250)
        {IIC_Stop();
            return 1;
        }
    }
    IIC_SCL=0;// 时钟输入 0        
    return 0;  
} 

/*******************************************************************************
* 函 数 名         : IIC_Ack
* 函数性能           : 产生 ACK 应答  
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void IIC_Ack(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=0;
    delay_us(2);
    IIC_SCL=1;
    delay_us(5);
    IIC_SCL=0;
}

/*******************************************************************************
* 函 数 名         : IIC_NAck
* 函数性能           : 产生 NACK 非应答  
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/            
void IIC_NAck(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=1;
    delay_us(2);
    IIC_SCL=1;
    delay_us(5);
    IIC_SCL=0;
}    

/*******************************************************************************
* 函 数 名         : IIC_Send_Byte
* 函数性能           : IIC 发送一个字节 
* 输    入         : txd:发送一个字节
* 输    出         : 无
*******************************************************************************/          
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
    SDA_OUT();         
    IIC_SCL=0;// 拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {if((txd&0x80)>0) //0x80  1000 0000
            IIC_SDA=1;
        else
            IIC_SDA=0;
        txd<<=1;       
        delay_us(2);   // 对 TEA5767 这三个延时都是必须的
        IIC_SCL=1;
        delay_us(2); 
        IIC_SCL=0;    
        delay_us(2);
    }     
} 

/*******************************************************************************
* 函 数 名         : IIC_Read_Byte
* 函数性能           : IIC 读一个字节 
* 输    入         : ack= 1 时,发送 ACK,ack=0,发送 nACK 
* 输    出         : 应答或非应答
*******************************************************************************/  
u8 IIC_Read_Byte(u8 ack)
{
    u8 i,receive=0;
    SDA_IN();//SDA 设置为输出
    for(i=0;i<8;i++)
    {
        IIC_SCL=0; 
        delay_us(2);
        IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
        delay_us(1); 
    }                     
    if (!ack)
        IIC_NAck();// 发送 nACK
    else
        IIC_Ack(); // 发送 ACK   
    return receive;
}

  • AT24C 代码
#include "24cxx.h"
#include "SysTick.h"

/*******************************************************************************
* 函 数 名         : AT24CXX_Init
* 函数性能           : AT24CXX 初始化
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void AT24CXX_Init(void)
{IIC_Init();//IIC 初始化
}

/*******************************************************************************
* 函 数 名         : AT24CXX_ReadOneByte
* 函数性能           : 在 AT24CXX 指定地址读出一个数据
* 输    入         : ReadAddr: 开始读数的地址 
* 输    出         : 读到的数据
*******************************************************************************/
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{                  
    u8 temp=0;                                                                                   
    IIC_Start();  
    if(EE_TYPE>AT24C16)
    {IIC_Send_Byte(0XA0);       // 发送写命令(最低位为 0,对从器件写)IIC_Wait_Ack();
        IIC_Send_Byte(ReadAddr>>8);// 发送高地址        
    }
    else 
    {IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   // 发送器件地址 0XA0, 写数据
    }        
    IIC_Wait_Ack(); 
  IIC_Send_Byte(ReadAddr%256);   // 发送低地址
    IIC_Wait_Ack();        
    IIC_Start();                              // 反复的起始条件,从设施进入发送模式    
    IIC_Send_Byte(0XA1);                 // 发送器件地址并且最初一位为 1,对从器件读                   
    IIC_Wait_Ack();     
  temp=IIC_Read_Byte(0);           
  IIC_Stop();// 产生一个进行条件        
    return temp;
}

/*******************************************************************************
* 函 数 名         : AT24CXX_WriteOneByte
* 函数性能           : 在 AT24CXX 指定地址写入一个数据
* 输    入         : WriteAddr  : 写入数据的目标地址 
                     DataToWrite: 要写入的数据
* 输    出         : 无
*******************************************************************************/
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{IIC_Start();  
    if(EE_TYPE>AT24C16)
    {IIC_Send_Byte(0XA0);        // 发送写命令
        IIC_Wait_Ack();
        IIC_Send_Byte(WriteAddr>>8);// 发送高地址      
    }
    else 
    {IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   // 发送器件地址 0XA0, 写数据
    }      
    IIC_Wait_Ack();       
  IIC_Send_Byte(WriteAddr%256);   // 发送低地址
    IIC_Wait_Ack();                                                           
    IIC_Send_Byte(DataToWrite);     // 发送字节                               
    IIC_Wait_Ack();                     
  IIC_Stop();// 产生一个进行条件 
    delay_ms(10);     
}

/*******************************************************************************
* 函 数 名         : AT24CXX_WriteLenByte
* 函数性能           : 在 AT24CXX 外面的指定地址开始写入长度为 Len 的数据
                     用于写入 16bit 或者 32bit 的数据
* 输    入         : WriteAddr  : 写入数据的目标地址 
                     DataToWrite: 要写入的数据
                     Len        : 要写入数据的长度 2,4
* 输    出         : 无
*******************************************************************************/
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
{      
    u8 t;
    for(t=0;t<Len;t++)
    {AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
    }                                                    
}

/*******************************************************************************
* 函 数 名         : AT24CXX_ReadLenByte
* 函数性能           : 在 AT24CXX 外面的指定地址开始读出长度为 Len 的数据
                     用于读出 16bit 或者 32bit 的数据
* 输    入         : ReadAddr   : 开始读出的地址 
                     Len        : 要读出数据的长度 2,4
* 输    出         : 读取的数据
*******************************************************************************/
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
{      
    u8 t;
    u32 temp=0;
    for(t=0;t<Len;t++)
    {
        temp<<=8;
        temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);                         
    }
    return temp;                                                    
}

/*******************************************************************************
* 函 数 名         : AT24CXX_Check
* 函数性能           : 查看 AT24CXX 是否失常
* 输    入         : 无
* 输    出         : 1: 检测失败,0: 检测胜利
*******************************************************************************/
u8 AT24CXX_Check(void)
{
    u8 temp;
    temp=AT24CXX_ReadOneByte(255);// 防止每次开机都写 AT24CXX               
    if(temp==0x36)return 0;           
    else// 排除第一次初始化的状况
    {AT24CXX_WriteOneByte(255,0X36);
        temp=AT24CXX_ReadOneByte(255);      
        if(temp==0X36)return 0;
    }
    return 1;                                              
}

/*******************************************************************************
* 函 数 名         : AT24CXX_Read
* 函数性能           : 在 AT24CXX 外面的指定地址开始读出指定个数的数据
* 输    入         : ReadAddr : 开始读出的地址 对 24c02 为 0~255
                     pBuffer  : 数据数组首地址
                     NumToRead: 要读出数据的个数
* 输    出         : 无
*******************************************************************************/
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{while(NumToRead)
    {*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);    
        NumToRead--;
    }
} 

/*******************************************************************************
* 函 数 名         : AT24CXX_Write
* 函数性能           : 在 AT24CXX 外面的指定地址开始写入指定个数的数据
* 输    入         : WriteAddr : 开始写入的地址 对 24c02 为 0~255
                     pBuffer  : 数据数组首地址
                     NumToRead: 要读出数据的个数
* 输    出         : 无
*******************************************************************************/
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{while(NumToWrite--)
    {AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
        WriteAddr++;
        pBuffer++;
    }
}


退出移动版