[PIC®/AVR®/dsPIC®产品]

【CuriosityNano测评报告】共三期 第二期 2.IIC+SPI+串口测试

[复制链接]
4948|35
手机看帖
扫描二维码
随时随地手机跟帖
zhangjiantao|  楼主 | 2021-6-15 18:28 | 显示全部楼层 |阅读模式
本帖最后由 zhangjiantao 于 2021-6-15 22:39 编辑

#申请原创#  距离第一次更新已半月有余,趁着端午假期把第二期的测评写下
本次的测评主要针对串口,I2C,SPI等外设进行测评,
测评内容:
1.   读取WQ25Q32的ID测试SPI功能是否可以准确读出ID数据通过串口打印出来
    SPI的配置,用到的函数
2.   I2C测试I2C器件的读写(DS3231,AT24C512)挂在一条总线上,并将读取的内容通过串口2打印出来
       串口的配置,PPS,PMD,寄存器,TRIS寄存器,等 I2C的配置,用到的函数

3.   外部中断测试,利用EVB板上的功能实现外部中断的功能,如果发生外部中断,串口发送(发送内容为:External Interrupt Occurrence)

测评流程

          按键修改.PNG                   
    修改下开发板上的按键,以便测试外部中断(下降沿)                  

     

测试流程

测试流程

  测试流程
1.   建立工程用MCC生成初始化代码
    PIN.PNG       
              引脚选择                                               

       外部INT.PNG
INT0下降沿选择

系统时钟初始化:选择HF时钟,外部中断引脚选择,初始化配置选择上升沿下降沿,这里进用到INT0,MCC是三个都生成了,可以在代码中修改
串口初始化:使能发送接收,波特率115200(这里的波特率会有个误码率,如果波特率不想有误码率可以再自己的系统中采用11.0592M的晶振),打开接收中断,发送采用查询方式
       USART2.PNG       
定时器1初始化(上一个PWM测评用了定时器0,这里用定时器1),时钟选择FOSC/4,定时时间选择10ms(115200的波特率,理论上每秒传输115200个bit,换算成字节大概是每秒可以传输11520左右个字节,因此接收一个字节的时间大概是0.1ms不到,这里设置成10ms,认为10ms没有接收到新的数据,则认为1帧数据传输完成,具体的数据可以根据实际的项目进行调整)打开中断,但不使能,主要用在串口清BUFFER的,所以串口接收时打开定时器1,
       TMR1.PNG    
定时器1

   TMR0.PNG    
定时器0
   PWM.PNG
    PWM (代码中包含上期的测评内容,把这个也放进来)                                                                                                                     
I2C初始化,时钟选择MFINTOSC(100k)主模式,满足大多数I2C从设备的时钟要求,
                      I2C.PNG
SPI初始化,时钟选择FOSC/4,SPI波特率0x9F(SPI时钟的计算为SPI_FOSC/2*(BGR+1)),注意TXR,RXR位置1

                      SPI.PNG
⑥ 重新定义putch,以便使用 printf,只需再定义的地方,引用头文件#include <stdio.h>,printf很好用,输出各种格式的字符,具体的使用大全和输出格式可百度



测试APP的代码和函数
如下
以下几张图是测试用到的器件一些关键性的参数,比如I2C的地址,和器件ID命令之类的。个人习惯,测试一个片子喜欢读他的ID号,至少可以验证自己的读写时序是对的


    AT24C512地址.PNG
       AT24C512 的7位地址0x50           
     
            DS3231I2C读写+地址.PNG                      
           DS3231 的7位地址0x68  
       W25Q32.PNG
   W25Q32     命令90:读取到的数据应该为 0x EF15



pps配置如下

    U2RXPPS = 0x13;   //RC3->UART2:RX2;    
    RB6PPS = 0x21;   //RB6->I2C1:SCL1;   
    INT0PPS = 0x10;   //RC0->EXT_INT:INT0;   
    RC1PPS = 0x0A;   //RC1->PWM1_16BIT:PWM11;   
    RB4PPS = 0x22;   //RB4->I2C1:SDA1;   
    RC2PPS = 0x13;   //RC2->UART2:TX2;   
//  INT2PPS = 0x12;   //RC2->EXT_INT:INT2;   
//  INT1PPS = 0x11;   //RC1->EXT_INT:INT1;   
    I2C1SCLPPS = 0x0E;   //RB6->I2C1:SCL1;   
//  PWMIN1PPS = 0x13;   //RC3->PWM1_16BIT:PWMIN1;   
//  PWMIN0PPS = 0x15;   //RC5->PWM1_16BIT:PWMIN0;   
    SPI1SC**S = 0x16;   //RC6->SPI1:SCK1;   
    I2C1SDAPPS = 0x0C;   //RB4->I2C1:SDA1;   
    RC5PPS = 0x1C;   //RC5->SPI1:SDO1;   
    RC6PPS = 0x1B;   //RC6->SPI1:SCK1;   
    SPI1SDIPPS = 0x14;   //RC4->SPI1:SDI1;   


测试函数,主函数直接调用即可
#include "APP.h"
//宏定义
#define W25QXX_CS  LATCbits.LATC7
#define DS3231_Addr     0x68
#define AT24C512_Addr   0x50
//本函数内调用的变量
uint8_t AT24C512_TestData[12] = {0x00,0x00,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x30};
uint8_t AT24C512_READ_TestData[10] = {0};
uint8_t DS3231_Time_buf[7];
uint8_t DS3231_Write_buf1[8]={0x00,0,30,15,2,15,6,21};
uint8_t DS3231_Write_buf[8];
//函数声明
void SPI_W25Q32_Flash_Test(void);
void I2C_DS3231_AT24C512_Test(void);
uint8_t Num_BCD(uint8_t data);
uint8_t BCD_Num(uint8_t data);
void AT24C512_Write1Byte_Any_Address(i2c1_address_t address, uint16_t Addr,uint8_t data);
uint8_t AT24C512_Read1Byte_Any_Address(i2c1_address_t address, uint16_t Addr);
void External_interrupt_test(void);


void PIC18F16Q40_Test(void)
{
    SPI_W25Q32_Flash_Test();     //SPI测试函数
    I2C_DS3231_AT24C512_Test();//I2C,DS3231,AT24C512
    External_interrupt_test();         //外部按键
}

<b>void SPI_W25Q32_Flash_Test(void)
{
    printf("----------------SPI_W25Q32_Flash_Test---------------------\n\r");
    uint8_t Temp = 0;
    uint8_t W25Q32_ID_Buf[2];
    uint16_t W25Q32_ID;
    W25QXX_CS=0;
    Temp=SPI1_ExchangeByte(0x90); //命令
    Temp=SPI1_ExchangeByte(0x00); //24位地址
    Temp=SPI1_ExchangeByte(0x00);     
    Temp=SPI1_ExchangeByte(0x00);
    W25Q32_ID_Buf[0]=SPI1_ExchangeByte(0x00);//发送无用的数据,可以为任何数据,主要是为了产生时钟SCLK
    W25Q32_ID_Buf[1]=SPI1_ExchangeByte(0x00);
    W25Q32_ID=W25Q32_ID_Buf[0]*256+W25Q32_ID_Buf[1];
    W25QXX_CS=1;
    printf("----------------SPI_W25Q32_Flash_ID:0x%X----------------\n\r",W25Q32_ID);
}

void I2C_DS3231_AT24C512_Test(void)
{
    uint8_t Temp = 0;
    printf("----------------I2C_AT24C512_EEPROM_Test-------------------\n\r");
    printf("----------------I2C_AT24C512_Write--------------------------\n\r");
    printf("AT24C512_Write_DATA:%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n\r",AT24C512_TestData[2],AT24C512_TestData[3],\
                                                                               AT24C512_TestData[4],AT24C512_TestData[5],\
                                                                               AT24C512_TestData[6],AT24C512_TestData[7],\
                                                                               AT24C512_TestData[8],AT24C512_TestData[9],\
                                                                               AT24C512_TestData[10],AT24C512_TestData[11]);
    I2C1_WriteNBytes(AT24C512_Addr, AT24C512_TestData, sizeof(AT24C512_TestData));
    DELAY_milliseconds(10);
    printf("----------------I2C_AT24C512_Read-----------------------------\n\r");
    I2C1_WriteNBytes(AT24C512_Addr, AT24C512_TestData, 2);
    I2C1_ReadNBytes(AT24C512_Addr, AT24C512_READ_TestData,sizeof(AT24C512_READ_TestData));   
    printf("AT24C512_Read_DATA:%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n\r", AT24C512_READ_TestData[0],AT24C512_READ_TestData[1],\
                                                                               AT24C512_READ_TestData[2],AT24C512_READ_TestData[3],\
                                                                               AT24C512_READ_TestData[4],AT24C512_READ_TestData[5],\
                                                                               AT24C512_READ_TestData[6],AT24C512_READ_TestData[7],\
                                                                               AT24C512_READ_TestData[8],AT24C512_READ_TestData[9]);
    printf("----------------Write data to any address----------------------------\n\r");
   
    printf("----------------Write 0x45 to 0x1001----------------------------\n\r");
    AT24C512_Write1Byte_Any_Address(AT24C512_Addr, 0x1001,0x45);
    DELAY_milliseconds(10);
    printf("----------------Read data From any address----------------------------\n\r");
    printf("----------------Read data From 0x1001----------------------------\n\r");
    Temp = AT24C512_Read1Byte_Any_Address(AT24C512_Addr, 0x1001);
    printf("----------------address 0x1001 data:0x%X----------------\n\r",Temp);
    printf("----------------I2C_AT24C512_EEPROM_Test OVER-------------------\n\r");
    printf("----------------Read time From DS3231----------------------------\n\r");
    I2C1_ReadDataBlock(DS3231_Addr,0,DS3231_Time_buf,7);
    printf("DS321_time:20%d.%d.%d  %d:%d:%d\t%d\n\r", BCD_Num(DS3231_Time_buf[6]),BCD_Num(DS3231_Time_buf[5]),\
                                                       BCD_Num(DS3231_Time_buf[4]),BCD_Num(DS3231_Time_buf[2]),\
                                                       BCD_Num(DS3231_Time_buf[1]),BCD_Num(DS3231_Time_buf[0]),\
                                                       BCD_Num(DS3231_Time_buf[3]));
   
    printf("Write time:2021.06.15 15:30:00 Tue to DS3231----------------------------\n\r");
    DS3231_Write_buf[0]=Num_BCD(DS3231_Write_buf1[0]);
    DS3231_Write_buf[1]=Num_BCD(DS3231_Write_buf1[1]);
    DS3231_Write_buf[2]=Num_BCD(DS3231_Write_buf1[2]);
    DS3231_Write_buf[3]=Num_BCD(DS3231_Write_buf1[3]);
    DS3231_Write_buf[4]=Num_BCD(DS3231_Write_buf1[4]);
    DS3231_Write_buf[5]=Num_BCD(DS3231_Write_buf1[5]);
    DS3231_Write_buf[6]=Num_BCD(DS3231_Write_buf1[6]);
    DS3231_Write_buf[7]=Num_BCD(DS3231_Write_buf1[7]);
    I2C1_WriteNBytes(DS3231_Addr, DS3231_Write_buf, 8);
    DELAY_milliseconds(10);
     I2C1_ReadDataBlock(DS3231_Addr,0,DS3231_Time_buf,7);
    printf("DS321_time:20%d.%d.%d  %d:%d:%d\t%d\n\r", BCD_Num(DS3231_Time_buf[6]),BCD_Num(DS3231_Time_buf[5]),\
                                                       BCD_Num(DS3231_Time_buf[4]),BCD_Num(DS3231_Time_buf[2]),\
                                                       BCD_Num(DS3231_Time_buf[1]),BCD_Num(DS3231_Time_buf[0]),\
                                                       BCD_Num(DS3231_Time_buf[3]));
    printf("----------------I2C Test over----------------------------\n\r");
}</b>

/****************************************************************************
* 功    能:10进制数据转换为BCD码
* 名    称:Num_BCD(uint8_t data)
* 说    明:用在时钟DS3231处。
****************************************************************************/
uint8_t Num_BCD(uint8_t data)
{
    uint8_t i,j,k;
    i=data/10;
    j=data%10;
    k=j+(i<<4);
    return k;
}

/****************************************************************************
* 功    能:BCD码转换为10进制数据
* 名    称:BCD_Num(uint8_t data)
* 说    明:用在时钟DS3231处。
****************************************************************************/
uint8_t BCD_Num(uint8_t data)
{
    uint8_t i;
    i=data&0x0F;
    data=data>>4;
    data&=0x0F;
    data*=10;
    i+=data;
    return i;
}

<b>void putch( char byte)//将串口跟 printf() 联系起来即重定向printf函数
{

    U2CON0bits.TXEN=1;
    while(!UART2_is_tx_ready());
    U2TXB=byte;
    U2CON0bits.TXEN=0;
}</b>

void AT24C512_Write1Byte_Any_Address(i2c1_address_t address, uint16_t Addr,uint8_t data)
{
    uint8_t databuf[3];
    databuf[0]=(uint8_t)(Addr/256);
    databuf[1]=(uint8_t)(Addr%256);
    databuf[2]=data;
    while(!I2C1_Open(address)); // sit here until we get the bus..
    I2C1_SetBuffer(databuf,3);
    I2C1_SetAddressNackCallback(NULL,NULL); //NACK polling?
    I2C1_MasterWrite();
    while(I2C1_BUSY == I2C1_Close()); // sit here until finished.
}
uint8_t AT24C512_Read1Byte_Any_Address(i2c1_address_t address, uint16_t Addr)
{
    uint8_t AddrBuf[2];
    uint8_t TEM=0;
    AddrBuf[0]=Addr/256;
    AddrBuf[1]=(uint8_t)(Addr%256);
    I2C1_WriteNBytes(address, AddrBuf, 2);
    I2C1_ReadNBytes(address, &TEM, 1);
    return TEM;
}

void External_interrupt_test(void)
{
    printf("MCU sleep when the external interrupt wakes up to continue to execute\n\r");
    asm("SLEEP"); //休眠模式
    NOP();
    NOP();
    printf("------------- KEY-------------------\n\r");
   
}



测试效果如下:
  1.  读取到正确的W25Q32 的ID:0xEF15  并通过串口打印出来
  2.  写入数据并读取出来,测试数据的写入和读取  并通过串口打印出来
  3. 以上两步执行完成,直接休眠直到外部中断唤醒(外部中断唤醒发送:External Interrupt Occurrence)

上期的PWM呼吸灯也在此部分代码里,一并上传,MCC趋势很方便,生成的可以跑起来,具体的实现可以通过函数的调用来实现功能


代码

PIC18F16Q40EVB.X.zip (3.16 MB)

使用特权

评论回复
chenqianqian| | 2021-6-15 20:22 | 显示全部楼层
讲解详细,赞一个。

使用特权

评论回复
51xlf| | 2021-7-3 16:42 | 显示全部楼层
使用的是硬件的吗?   

使用特权

评论回复
评论
zhangjiantao 2021-7-6 21:42 回复TA
硬件的 
i1mcu| | 2021-7-3 16:42 | 显示全部楼层
IIC最大速率是多少   

使用特权

评论回复
pmp| | 2021-7-3 16:43 | 显示全部楼层
做个逻。辑。 分析仪吧

使用特权

评论回复
mmbs| | 2021-7-3 16:43 | 显示全部楼层
读取flash的效果怎样   

使用特权

评论回复
1988020566| | 2021-7-3 16:43 | 显示全部楼层
讲解详细,赞一个。  

使用特权

评论回复
lzbf| | 2021-7-3 16:43 | 显示全部楼层
测评的效果不错啊。      

使用特权

评论回复
houjiakai| | 2021-7-3 16:44 | 显示全部楼层
能够做U盘吗?        

使用特权

评论回复
jimmhu| | 2021-7-3 16:44 | 显示全部楼层
            

使用特权

评论回复
cemaj| | 2021-7-3 16:44 | 显示全部楼层
最大的频率是多少        

使用特权

评论回复
youtome| | 2021-7-3 16:44 | 显示全部楼层
能够解析json数组吗?         

使用特权

评论回复
评论
zhangjiantao 2021-7-6 21:45 回复TA
可以 解析,可能比较复杂 用八位的MCU来实现 
凯复Kane| | 2021-7-7 14:59 | 显示全部楼层
好详细的测评 流程可以参考一下吗 以后我测评就按这个来了

使用特权

评论回复
usysm| | 2021-8-7 12:14 | 显示全部楼层
单片机模拟SPI的?

使用特权

评论回复
typeof| | 2021-8-7 12:15 | 显示全部楼层
pic单片机通过IIC对24c02写操作

使用特权

评论回复
yujielun| | 2021-8-7 12:16 | 显示全部楼层
spi和I2c的速率是多少?

使用特权

评论回复
kkzz| | 2021-8-7 12:16 | 显示全部楼层
总结的非常不错。

使用特权

评论回复
pklong| | 2021-8-7 12:17 | 显示全部楼层
怎么确定pic单片机工作在spi还是i2c模式  

使用特权

评论回复
touser| | 2021-8-7 12:17 | 显示全部楼层
rs232速率一般最大115200  

使用特权

评论回复
myiclife| | 2021-8-7 12:18 | 显示全部楼层
接触比较多的是IIC和SPI接口

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

55

帖子

1

粉丝