目 录
一、实验目的
二、实验仪器及器件
三、实验内容及原理
四、实验步骤
五、实验测试数据表格记录
六、实验数据分析及处理
七、实验结论与感悟
一、实验目的
使用FPGA/ARM实现SPI数据传输实验;实现数据传输程序的编写、下载、传输验证、传输波形测量,发送的数据及其数据传送过程须通过示波器测量波形验证正确性。
基本要求:
1、掌握SPI数据传输的理论基础;
2、掌握数据传输程序的编写方法;
3、掌握数据传输程序的下载与验证方法;
4、掌握示波器测量波形的正确方法;
5、掌握示波器波形的分析方法。
二、实验仪器及器件
- 电脑(Windows 10)
- PSI-STP-ST-STM32F103实验箱(ARM)
- 示波器
三、实验内容及原理
实验内容:基于SPI的DS1302实时时钟显示实验
使用ARM实验箱实现SPI数据传输实验;实现数据传输程序的编写、仿真、下载、传输验证;传输波形测量,发送的数据及其数据传送过程须通过示波器测量波形验证正确性。
说明:DS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟芯片,附加31字节静态RAM,采用SPI三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。实时时钟可提供秒、分、时、星期、日、月和年。
要求:
(1)实现DS1302控制输出时钟,并将其用数码管显示时钟时间,精确到秒;
(2)掌握示波器测量方法,利用示波器测量波形,要求测量出SPI控制时序图。
图3.1 STM32F103实验箱 |
实验原理:
DS1302 是美国 DALLAS 公司推出的一种高性能、低功耗的实时时钟芯片,附加 31 字节静态 RAM,采用 SPI 三线接口与 CPU 进行同步通信,并可采用突发方式一次传送多个字节的时钟信号和 RAM 数据。实时时钟可提供秒、分、时、星期、日、月和年,一个月小与 31 天时可以自动调整,且具有闰年补偿功能。工作电压宽达 2.5~5.5V。采用双电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后背电源进行涓细电流充电的能力。DS1302 的外部引脚分配如下图所示。DS1302 用于数据记录,特别是对某些具有特殊意义的数据点的记录上,能实现数据与出现该数据的时间同时记录,因此广泛应用于测量系统中。
图3.2 DS1302引脚图 |
四、实验步骤
- 建立工程,新建文件夹命名为“基于SPI的DS1302实时时钟显示实验”,核心处理器芯片是 STM32F103ZC。
- 添加库文件,在工程文件夹中新建 4 个文件夹为 CORE、OBJ、STM32F10X_FELIB,SYSTEM,并在官方固件库包中相关的库包复制进去。
图4.1 工程目录浏览
- 配置工程。
-
编写相关程序。
- 编译程序,如果有报错,逐错修改直至没有错误。
- 在线下载调试,代码烧写完成后按下复位键(RESET),可以看到数码管从初始化好的时钟时间,精确到秒显示(初始化时间为2023年5月1日19点59分49秒,星期一):
图4.4 实验现象数码管显示时钟(21时12分05秒)
7.利用示波器测量波形,测量出SPI控制时序图。
图4.5 试验箱DS1302@SPI
a.时钟数据的读写地址
图4.2 时钟数据的读写地址 |
如上图,为DS1302芯片的时钟数据的读和写的地址,也就是说要实现对芯片控制,就是往这些地址上写入或读出数据。其中:
读地址为0x81(秒), 0x83(分), 0x85(时), 0x87(日), 0x89(月), 0x8b(星期), 0x8d(年);
写地址为0x80(秒), 0x82(分), 0x84(时), 0x86(日), 0x88(月), 0x8a(星期), 0x8c(年)。
DS1302控制软件最基本的操作为写函数和读函数,其次就是实现初始化函数
读写时序
图 单字节读操作时序图
图 单字节写操作时序图 |
ds1302.c关键代码段1:读取一个地址的数据
// 从ds1302的内部寄存器addr读出一个值,作为返回值
u8 DS1302_Read_Byte(u8 addr)
{
u8 i,temp;
DS1302_RST = 0; //停止DS1302总线
delay_us(10);
DS1302_RST = 1; //启动DS1302总线
addr = addr | 0x01; //读数据
DS1302_IO_OUT();
for(i = 0; i < 8; i ++) //写地址
{
if (addr & 0x01) // 从低位开始传输的
DS1302_DATA_OUT = 1;
else
DS1302_DATA_OUT = 0;
DS1302_SCK = 1;
delay_us(10);
DS1302_SCK = 0;
delay_us(10);
addr = addr>>1; // 把addr右移一位
}
DS1302_IO_IN();
for (i = 0; i < 8; i ++) //读数据
{
temp = temp >> 1;
if(DS1302_DATA_IN) // 读出来的数值是低位在前的
temp |= 0x80;
else
temp &= 0x7F;
DS1302_SCK = 1;
delay_us(10);
DS1302_SCK = 0;
delay_us(10);
}
DS1302_RST = 0; // RST拉低意味着一个大周期的结束
return temp;
}
ds1302.c关键代码段2:向DS1302命令(地址+数据)
//向DS1302写入一个字节数据
void DS1302_Write_Byte(u8 addr, u8 data)
{
u8 i;
DS1302_RST = 0; //停止DS1302总线
delay_us(10);
DS1302_RST = 1; //启动DS1302总线
addr = addr & 0xFE;
DS1302_IO_OUT();
//写地址addr
for(i = 0; i < 8; i ++)
{
if (addr & 0x01) // 从低位开始传输的
DS1302_DATA_OUT = 1;
else
DS1302_DATA_OUT = 0;
DS1302_SCK = 1; // 制造上升沿
delay_us(10);
DS1302_SCK = 0; // 把SCLK拉低
delay_us(10);
addr = addr>>1; // 把addr右移一位
}
// 写数据data
for (i = 0; i < 8; i ++)
{
if(data & 0x01) //SPI是从低位开始传输的
DS1302_DATA_OUT = 1;
else
DS1302_DATA_OUT = 0;
DS1302_SCK = 1; // 制造上升沿
delay_us(10);
DS1302_SCK = 0;
delay_us(10);
data = data>>1; // 把addr右移一位
}
DS1302_RST = 0; // RST拉低
}
ds1302.c关键代码段3:初始化时钟
//初始时间 20 23年 5月 1日 19点 59分49秒,星期1
u8 time_buf[8] = {0x20,0x23,0x05,0x01,0x11,0x08,0x56,0x01};
//向DS1302写入时间数据
void DS1302_Write_Time(void)
{
DS1302_Write_Byte(ds1302_control_add, 0x00); //关闭写保护
// DS1302_Write_Byte(ds1302_sec_add, 0x80); //暂停时钟
//DS1302_Write_Byte(ds1302_charger_add, 0xA9); //涓流充电
DS1302_Write_Byte(ds1302_year_add,time_buf[1]); //年
DS1302_Write_Byte(ds1302_month_add,time_buf[2]); //月
DS1302_Write_Byte(ds1302_date_add,time_buf[3]); //日
DS1302_Write_Byte(ds1302_hr_add,time_buf[4]); //时
DS1302_Write_Byte(ds1302_min_add,time_buf[5]); //分
DS1302_Write_Byte(ds1302_sec_add,time_buf[6]); //秒
DS1302_Write_Byte(ds1302_day_add,time_buf[7]); //周
DS1302_Write_Byte(ds1302_control_add,0x80); //打开写保护
}
seg.c关键代码段:
void show(u8 pl)
{
BitAction sum[8];
u8 i;
for(i=0;i<8;i++)
{
if((data[pl]>>i)&0x01 == 0x1)
sum[i] = Bit_SET;
else
sum[i] = Bit_RESET;
}
GPIO_WriteBit(GPIOG,GPIO_Pin_8,sum[7]);
GPIO_WriteBit(GPIOC,GPIO_Pin_6,sum[6]);
GPIO_WriteBit(GPIOC,GPIO_Pin_7,sum[5]);
GPIO_WriteBit(GPIOA,GPIO_Pin_8,sum[4]);
GPIO_WriteBit(GPIOG,GPIO_Pin_4,sum[3]);
GPIO_WriteBit(GPIOG,GPIO_Pin_5,sum[2]);
GPIO_WriteBit(GPIOG,GPIO_Pin_6,sum[1]);
GPIO_WriteBit(GPIOG,GPIO_Pin_7,sum[0]);
}
main.c关键代码
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "12864.h"
#include "ds1302.h"
#include "seg.h"
u8 time[15];
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
DS1302_Init();
delay_ms(10);
DS1302_Write_Time();
delay_ms(10);
Geg_GPIO_Configuration();
while(1)
{
//DS1302_Get_Time(time);
show(time[9]);//时
GPIO_SetBits(GPIOF,GPIO_Pin_13);
GPIO_ResetBits(GPIOG,GPIO_Pin_0);
GPIO_ResetBits(GPIOE,GPIO_Pin_9);
GPIO_ResetBits(GPIOF,GPIO_Pin_12);
GPIO_ResetBits(GPIOE,GPIO_Pin_8);
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
GPIO_ResetBits(GPIOE,GPIO_Pin_10);
GPIO_ResetBits(GPIOF,GPIO_Pin_11);
delay_ms(1);
show(time[10]);//时
GPIO_ResetBits(GPIOF,GPIO_Pin_13);
GPIO_SetBits(GPIOG,GPIO_Pin_0);
GPIO_ResetBits(GPIOE,GPIO_Pin_9);
GPIO_ResetBits(GPIOF,GPIO_Pin_12);
GPIO_ResetBits(GPIOE,GPIO_Pin_8);
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
GPIO_ResetBits(GPIOE,GPIO_Pin_10);
GPIO_ResetBits(GPIOF,GPIO_Pin_11);
delay_ms(1);
show_x();//-
GPIO_ResetBits(GPIOF,GPIO_Pin_13);
GPIO_ResetBits(GPIOG,GPIO_Pin_0);
GPIO_SetBits(GPIOE,GPIO_Pin_9);
GPIO_ResetBits(GPIOF,GPIO_Pin_12);
GPIO_ResetBits(GPIOE,GPIO_Pin_8);
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
GPIO_ResetBits(GPIOE,GPIO_Pin_10);
GPIO_ResetBits(GPIOF,GPIO_Pin_11);
delay_ms(1);
show(time[11]);//min
GPIO_ResetBits(GPIOF,GPIO_Pin_13);
GPIO_ResetBits(GPIOG,GPIO_Pin_0);
GPIO_ResetBits(GPIOE,GPIO_Pin_9);
GPIO_SetBits(GPIOF,GPIO_Pin_12);
GPIO_ResetBits(GPIOE,GPIO_Pin_8);
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
GPIO_ResetBits(GPIOE,GPIO_Pin_10);
GPIO_ResetBits(GPIOF,GPIO_Pin_11);
delay_ms(1);
show(time[12]);//min
GPIO_ResetBits(GPIOF,GPIO_Pin_13);
GPIO_ResetBits(GPIOG,GPIO_Pin_0);
GPIO_ResetBits(GPIOE,GPIO_Pin_9);
GPIO_ResetBits(GPIOF,GPIO_Pin_12);
GPIO_SetBits(GPIOE,GPIO_Pin_8);
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
GPIO_ResetBits(GPIOE,GPIO_Pin_10);
GPIO_ResetBits(GPIOF,GPIO_Pin_11);
delay_ms(1);
show_x();//-
GPIO_ResetBits(GPIOF,GPIO_Pin_13);
GPIO_ResetBits(GPIOG,GPIO_Pin_0);
GPIO_ResetBits(GPIOE,GPIO_Pin_9);
GPIO_ResetBits(GPIOF,GPIO_Pin_12);
GPIO_ResetBits(GPIOE,GPIO_Pin_8);
GPIO_SetBits(GPIOE,GPIO_Pin_7);
GPIO_ResetBits(GPIOE,GPIO_Pin_10);
GPIO_ResetBits(GPIOF,GPIO_Pin_11);
delay_ms(1);
show(time[13]);//s
GPIO_ResetBits(GPIOF,GPIO_Pin_13);
GPIO_ResetBits(GPIOG,GPIO_Pin_0);
GPIO_ResetBits(GPIOE,GPIO_Pin_9);
GPIO_ResetBits(GPIOF,GPIO_Pin_12);
GPIO_ResetBits(GPIOE,GPIO_Pin_8);
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
GPIO_SetBits(GPIOE,GPIO_Pin_10);
GPIO_ResetBits(GPIOF,GPIO_Pin_11);
delay_ms(1);
show(time[14]);//s
GPIO_ResetBits(GPIOF,GPIO_Pin_13);
GPIO_ResetBits(GPIOG,GPIO_Pin_0);
GPIO_ResetBits(GPIOE,GPIO_Pin_9);
GPIO_ResetBits(GPIOF,GPIO_Pin_12);
GPIO_ResetBits(GPIOE,GPIO_Pin_8);
GPIO_ResetBits(GPIOE,GPIO_Pin_7);
GPIO_ResetBits(GPIOE,GPIO_Pin_10);
GPIO_SetBits(GPIOF,GPIO_Pin_11);
delay_ms(1);
}
}
由于篇幅原因,五、六、七见下篇
五、实验测试数据表格记录
六、实验数据分析及处理
七、实验结论与感悟