IIC、SPI小记

  • IIC

    • 简介

      • 该总线半双工,速度慢,多用于芯片之间通信。由数据线SDA和时钟SCL构成,可发送和接收数据。
      • 有三种类型信号:开始信号、结束信号和应答信号。
        • 开始信号:SCL为高电平时,SDA由高电平跳变为低电平,开始传送数据;
        • 结束信号:SCL为高电平时,SDA由低电平跳变为高电平,结束传送数据;
        • 应答信号:接收方收到8位数据后,向发送端发出低电平,表示数据收到。
    • 时序
    • 软件模拟IIC与24C02之间的通信
      • 写过程

        • 起始地址》》要写入的设备在吗》》要写入的数据地址在吗》》写入》》停止信号
      • 读过程
        • 起始信号》》要读的设备在吗》》要读的地址在吗》》要读的设备在吗》》读取数据》》停止信号
          • 注:这里要写两个设备地址,此两个地址只有前7bit真正表示地址,最后一位0表示写,1表示读,故设备地址不一样。
  • SPI
    • 简介

      • 高速、全双工同步总线,占用四根引脚
      • 若主机需读取数据,需要向从机发送空字节(0xff),与从机移位寄存器的数据进行交换。
    • 时序
      • 主从的时钟相位和极性应一致:CPOL=1,则空闲为高电平,CPPL=0,则空闲为低;CPHA=0,第一个边沿采集,CPHA=1,第二个边沿采集。
  • 软件模拟
    • IIC

      • void 24C02_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
        {
            IIC_Start();
            IIC_Send_Byte(0XA0);   //0XA0包括设备地址和写命令
            IIC_Wait_Ack();
            IIC_Send_Byte(WriteAddr);   //WriteAddr为写入数据的目的地址
            IIC_Wait_Ack();              //
            IIC_Send_Byte(DataToWrite);     //   DataToWrite写入的数据
            IIC_Wait_Ack();
            IIC_Stop();
            delay_ms(10);
        }
        u8 24C02_ReadOneByte(u16 ReadAddr)
        {
            u8 temp=0;
            IIC_Start();
            IIC_Send_Byte(0XA0);   //写入要读的设备地址
            IIC_Wait_Ack(); //
            IIC_Send_Byte(ReadAddr);   //
            IIC_Wait_Ack();        //
            IIC_Start();
            IIC_Send_Byte(0XA1);    //真正的读
            IIC_Wait_Ack();
            temp=IIC_Read_Byte(0);
            IIC_Stop();
            return temp;
        }
        void IIC_Send_Byte(u8 txd)//txd为待发送的数据
        {
            u8 t;
            SDA_OUT();
            IIC_SCL=0;//等待发送
            for(t=0;t<8;t++)
            {
                IIC_SDA=(txd&0x80)>>7;//取最高位开始发送
                txd<<=1;       //将已发送的移走,次高位变成最高位
                delay_us(2);   //
                IIC_SCL=1;
                delay_us(2);
                IIC_SCL=0;
                delay_us(2);
            }
        }
    • SPI
      • u8 SPI1_ReadWriteByte(u8 TxData)//TxData为要写入的命令或数据,写入命令,则一般返回值不采用,写入空字节,则为读取字节
        {
            u8 retry=0;
            while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //RESET为0,表示发送缓冲区非空,待发送数据无法写入
                {
                retry++;
                if(retry>200)return 0;
                }
            SPI_I2S_SendData(SPI1, TxData); //向SPI1写入命令或数据,在写之前要要保证发送缓冲区为空;
            retry=0;
            while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//RESET表示接收缓冲区无有效数据
                {
                retry++;
                if(retry>200)return 0;
                }
            return SPI_I2S_ReceiveData(SPI1); //    通过SPI1接收最近的数据,在接收之前要保证接收缓冲去包含有效数据
        }
        
        //读取SPI FLASH
        void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
        {
             u16 i;
            SPI_FLASH_CS=0;                            //片选
            SPI1_ReadWriteByte(W25X_ReadData);         //发送读取命令
            SPI1_ReadWriteByte((u8)((ReadAddr)>>16));  //·
            SPI1_ReadWriteByte((u8)((ReadAddr)>>8));
            SPI1_ReadWriteByte((u8)ReadAddr);
            for(i=0;i<NumByteToRead;i++)
            {
                pBuffer[i]=SPI1_ReadWriteByte(0XFF);   //循环读数
            }
            SPI_FLASH_CS=1;                            //      取消片选
        }  
        void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
        {
            u32 secpos;
            u16 secoff;
            u16 secremain;
             u16 i;    
        
            secpos=WriteAddr/4096;//一个扇区4096个地址,表示扇区地址
            secoff=WriteAddr%4096;//在扇区内偏移
            secremain=4096-secoff;//扇区剩余空间大小
            if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//如果无跨区
            while(1)
            {
                SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容
                for(i=0;i<secremain;i++)//校验数据
                {
                    if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除
                }
                if(i<secremain)//
                {
                    SPI_Flash_Erase_Sector(secpos);//擦除整个扇区
                    for(i=0;i<secremain;i++)       //
                    {
                        SPI_FLASH_BUF[i+secoff]=pBuffer[i];//
                    }
                    SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//更新扇区
        
                }else SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain);//
                if(NumByteToWrite==secremain)break;//
                    secpos++;//
                    secoff=0;//
                       pBuffer+=secremain;  //
                    WriteAddr+=secremain;//
                       NumByteToWrite-=secremain;                //
                    if(NumByteToWrite>4096)secremain=4096;    //
                    else secremain=NumByteToWrite;            //
                }
            };
        }
        
        
时间: 2024-10-29 19:07:28

IIC、SPI小记的相关文章

IIC SPI UART通信方式的区别

1.定义上的区别 IIC :Inter-Integrated Circuit   两线式串行总线 SPI : serial peripheral interface   串行外围设备接口 UART : Universal Asynchronous Receiver/Transmitter 通用异步收发传输器 通信速率 SPI > IIC > UART SPI : 串行时钟(SCLK).主机输入从机输出(MISO).主机输出从机输入(MOSI)两条合一的数据线,1个CS(设备片选线) 串行,同步

赛灵思官网资源导读

俗话说“授之鱼不如授之以渔”,看到这边有人要资料有人送资料的,其实论坛不更应该是一个交流的空间么?那就让找资料更有效率一点,让大家花更多时间来交流吧.言归正传,写这篇文章主要想介绍Xilinx各种资料的找法.分类方法和什么问题该看哪些资料.限于经验,难免有错漏,希望大家指出错误并继续补充.一.软件Xilinx的软件主要是ISE, EDK, ChipScope Pro, System Generator, PlanAhead, ModelSim,如果要算上AccelDSP也凑合,不过相信国内没多少

linux 时钟源初步分析linux kernel 时钟框架详细介绍

初步概念: 看datasheet的关于时钟与定时器的部分, FCLK供给cpu, HCLK供给AHB总线设备(存储器控制器,中断控制器.LCD控制器.DMA.USB主机控制器等), PCLK供给APB总线上的设备(watchdog.IIS.i2c. pwm.定时器.ADC.uart.gpio.rtc.spi) 上电时 fclk的时钟等于外部时钟fin, 然后等待LOCKTIME后, 依照MPLLCON寄存器的设置,倍频到高频. UPLLCON专用于USB同于MPLLCON. 关于分频: CLKD

关于STM32系统构架的一点见解

初学32,留下一点自己学习的记录,以便今后参考,大神指明错误不胜感激 一.首先说说STM32F10x芯片由丝印所体现出的共同点和区别. 先简单说说命名规则: 101基本型,102USB基本型,103增强型,105或107互联型. T:36脚,C:48脚,R:64脚,V:100脚,Z:144脚. C:256K SRAM, D:384K SRAM, E:512K SRAM. 我们正对芯片的丝印,会看到芯片左下角会有一个小圆点(正方向),有的在右上角会有一个稍大点的圆圈标记,靠近左下角小圆点的管脚号为

树莓派高级GPIO库,wiringpi2 for python使用笔记(三)GPIO操作

GPIO库的核心功能,当然就是操作GPIO了,GPIO就是"通用输入/输出"接口,比如点亮一个LED.继电器等,或者通过iic spi 1-wire等协议,读取.写入数据,这都是GPIO的用处,可以说没有GPIO,树莓派只能当小电脑用,有了GPIO,就升级成一个控制器了.先来说说怎么操作一个数字量(高低电平). 先看代码: import wiringpi2 as gpio from wiringpi2 import GPIO gpio.wiringPiSetup() #初始化 gpio

(五)Lua脚本语言入门

---恢复内容开始--- 写完这篇Lua脚本语言入门,自己就要尝试去用Lua脚本语言写esp8266了,,自己现在挺心急的,因为朋友使用esp8266本来说自己帮忙写好程序的,但是用的单片机不一样自己没有,没有办法测试,用AT指令就显得不方便,还要根据单片机改程序,,而且自己以前用感觉AT指令发信息那块,麻烦,,,,自己知道用脚本去操作8266要比AT指令灵活和稳定的多,真想赶紧学会用Lua脚本去操作8266,那样的话就可以很方便的帮到朋友了......本来答应了,,,,,,,竟然食言了....

单片机裸奔框架1

侃侃单片机的裸奔程序的框架!以下是我总结的一些东西,不合乎之处来请大家指点呀,本人第二次在21ic发帖,希望大家鼓励鼓励呀!! 从07年参加全国大学生电子设计大赛初次接触单片机开发至今已经有4年了,初学单片机时,都会纠结于其各个模块功能的应用,如串口(232,485)对各种功能IC的控制,电机控制PWM,中断应用,定时器应用,人机界面应用,CAN总线等. 这是一个学习过程中必需的阶段,是基本功.很庆幸,在参加电子设计大赛赛前培训时,MCU周围的控制都训练的很扎实.经过这个阶段后,后来接触不同的M

RK3288开发板PopMetal上的GPIO驱动实例

楼主在这边给大家介绍下如何使用PopMetal的GPIO.先讲过程,再讲原理吧, 该驱动需要涉及到的知识点:1,DTS设备树的作用,2,platform虚拟总线驱动的编写. 第一步,添加DTS节点 在/kernel/arch/arm/boot/dts/rockchip.dts下添加如下内容. 下图rockchip-leds-gpio这部分的内容,修改保存, 第二步,在kernel/drivers下创建个LED文件夹,然后加入如下几个文件驱动文件leds.c,Makefile和Kconfig.如下

linux 内核配置参考

对于每一个配置选项,用户可以回答"y"."m"或"n".其中"y"表示将相应特性的支持或设备驱动程序编译进内核:"m"表示将相应特性的支持或设备驱动程序编译成可加载模块,在需要时,可由系统或用户自行加入到内核中去:"n"表示内核不提供相应特性或驱动程序的支持.只有<>才能选择M 1. General setup(通用选项) [*]Prompt for development