本帖最后由 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)
测评流程
修改下开发板上的按键,以便测试外部中断(下降沿)
测试流程 1. 建立工程用MCC生成初始化代码 引脚选择
INT0下降沿选择
①系统时钟初始化:选择HF时钟,外部中断引脚选择,初始化配置选择上升沿下降沿,这里进用到INT0,MCC是三个都生成了,可以在代码中修改 ②串口初始化:使能发送接收,波特率115200(这里的波特率会有个误码率,如果波特率不想有误码率可以再自己的系统中采用11.0592M的晶振),打开接收中断,发送采用查询方式 ③定时器1初始化(上一个PWM测评用了定时器0,这里用定时器1),时钟选择FOSC/4,定时时间选择10ms(115200的波特率,理论上每秒传输115200个bit,换算成字节大概是每秒可以传输11520左右个字节,因此接收一个字节的时间大概是0.1ms不到,这里设置成10ms,认为10ms没有接收到新的数据,则认为1帧数据传输完成,具体的数据可以根据实际的项目进行调整)打开中断,但不使能,主要用在串口清BUFFER的,所以串口接收时打开定时器1, 定时器1
定时器0 PWM (代码中包含上期的测评内容,把这个也放进来) ④I2C初始化,时钟选择MFINTOSC(100k)主模式,满足大多数I2C从设备的时钟要求,
⑤SPI初始化,时钟选择FOSC/4,SPI波特率0x9F(SPI时钟的计算为SPI_FOSC/2*(BGR+1)),注意TXR,RXR位置1
⑥ 重新定义putch,以便使用 printf,只需再定义的地方,引用头文件#include <stdio.h>,printf很好用,输出各种格式的字符,具体的使用大全和输出格式可百度
测试APP的代码和函数
如下
以下几张图是测试用到的器件一些关键性的参数,比如I2C的地址,和器件ID命令之类的。个人习惯,测试一个片子喜欢读他的ID号,至少可以验证自己的读写时序是对的
AT24C512 的7位地址0x50
DS3231 的7位地址0x68
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)
视频不太会插,研究好了再插入视频,先上张图
|