前言
回顾下之前的章节:
第一章节中我们描述了整个框架的核心设计思路以及主要的文件架构
第二章节中我们基于一个简单的定时器OS实现了串口的数据打印,并完成了通用crc模块的设计和测试
第三章节中我们给出了真随机数和伪随机数的概念和代码示例,并在架构上对接口进行了重构
第四章节中我们回顾了FMC的基本知识,并给出了示例,后面我们将在设计IAP的时候再次使用到FMC
第五章节中我们使用ADC和DMA搭建了一个通用的采样框架,并通过串口给出了采样的数据示例
第六章节中我们总结了DAC的基本使用方法,并通过DAC生成了任意频率的正弦波,三角波和方波
第七章节中我们总结下时钟的概念,并给出了获取系统中各模块的时钟频率的代码
第八章节中我们介绍了如何通过串口的DMA来实现串口数据的收发
第九章节中我们介绍了定时器的使用,以及如何产生普通占空比PWM以及互补带死区的PWM,这在控制中十分重要
本文我们将介绍下SPI的概念,以及如何使用三线SPI的时序驱动DS1302时钟芯片,同时我们也将给出用模拟IO方式驱动DS1302的方法。
关键字:STM32,GD32,SPI,DS1302,三线SPI,半双工SPI
SPI
串行外设接口(Serial Peripheral Interface,缩写为SPI)提供了基于SPI协议的数据发送和接收功能,可以工作于主机或从机模式。SPI接口支持具有硬件CRC计算和校验的全双工和单工模式。有些SPI口还支持SPI四线主机模式。
常规的SPI信号描述如下图:
![b425cf56939af627684eb2e855b540d6.png](https://img-blog.csdnimg.cn/img_convert/b425cf56939af627684eb2e855b540d6.png)
DS1302
DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,并且具有闰年补偿等多种功能。(百度百科)
DS1302的管脚配置:
DS1302的时序:
![b9aa1cb946556777467c3906aae18f71.png](https://img-blog.csdnimg.cn/img_convert/b9aa1cb946556777467c3906aae18f71.png)
可以看到:除了CE高低电平不一样,这个时序跟半双工的SPI是一样的。
![282ba815fee14c8499c49948d654d99e.png](https://img-blog.csdnimg.cn/img_convert/282ba815fee14c8499c49948d654d99e.png)
DS1302的寄存器配置:
![c29fd8a6af66cd5e42cb27462928d099.png](https://img-blog.csdnimg.cn/img_convert/c29fd8a6af66cd5e42cb27462928d099.png)
DS1302的时钟频率:
![2d39088984fd70bea52cd5c6229d0954.png](https://img-blog.csdnimg.cn/img_convert/2d39088984fd70bea52cd5c6229d0954.png)
三线SPI驱动DS1302
半双工SPI的基本初始化:
单线发送模式
数据8位
主机模式
时钟空闲低电平,第一个边沿读数据
NSS Soft
分频:根据DS1302的配置来,一般1M多比较合适。
LSB
发送流程:
设置为发送模式
CE使能
发送地址
发送数据
CE失能
接收流程:
设置为发送模式
CE使能
发送地址
设置为接收模式
等待数据接收完成
CE失能
切换为发送模式,掐断SPI时钟信号
读数据,等待SPI收工
模拟IO驱动DS1302
从网上找的代码,其原理就是用IO口反转来模拟高低电平。
一坨代码
GD32代码:
#include "io.h"
#include "io_gd32.h"
#include "common.h"
//#define DS1302_USING_SPI
/* PF7-SCK PF8-CE PF9-DATA */
#define CURRENT_SPI SPI4
#define RTC_RCU RCU_GPIOF
#define RTC_GPIO GPIOF
#define RTC_SCK_PIN GPIO_PIN_7
#define RTC_CE_PIN GPIO_PIN_8
#define RTC_DATA_PIN GPIO_PIN_9
#ifdef DS1302_USING_SPI
#define READ_MODE spi_disable(CURRENT_SPI); \
spi_bidirectional_transfer_config(CURRENT_SPI, SPI_BIDIRECTIONAL_RECEIVE); \
spi_enable(CURRENT_SPI);
#define WRITE_MODE spi_disable(CURRENT_SPI); \
spi_bidirectional_transfer_config(CURRENT_SPI, SPI_BIDIRECTIONAL_TRANSMIT); \
spi_enable(CURRENT_SPI);
#define CE_HIGH gpio_bit_set(RTC_GPIO, RTC_CE_PIN);
#define CE_LOW gpio_bit_reset(RTC_GPIO, RTC_CE_PIN);
#else
#define READ_MODE gpio_init_input_mode(RTC_RCU, RTC_GPIO, RTC_DATA_PIN);
#define WRITE_MODE gpio_init_output_mode(RTC_RCU, RTC_GPIO, RTC_DATA_PIN, GPIO_OSPEED_50MHZ, 0);
#define CE_HIGH gpio_bit_set(RTC_GPIO, RTC_CE_PIN);
#define CE_LOW gpio_bit_reset(RTC_GPIO, RTC_CE_PIN);
#define CLK_HIGH gpio_bit_set(RTC_GPIO, RTC_SCK_PIN);
#define CLK_LOW gpio_bit_reset(RTC_GPIO, RTC_SCK_PIN);
#define DATA_HIGH gpio_bit_set(RTC_GPIO, RTC_DATA_PIN);
#define DATA_LOW gpio_bit_reset(RTC_GPIO, RTC_DATA_PIN);
#define DATA gpio_input_bit_get(RTC_GPIO, RTC_DATA_PIN)
#endif
#define WRITE_FLAG_ADDR 0xC0
#define READ_FLAG_ADDR 0xC1
#define RTC_INIT_FLAG 0xA5
#define YEAR_BASE 2021
/* 默认起始时间2021年1月1日,星期五 */
time_t init_time = {YEAR_BASE, 1, 1, 0, 0, 0, 5};
void spi1_init(){}
#ifdef DS1302_USING_SPI
void spi5_init(void)
{
spi_parameter_struct spi_init_struct;
spi_i2s_deinit(CURRENT_SPI);
rcu_periph_clock_enable(RCU_SPI4);
/* SPI_MOSI pf9 */
gpio_init_af_mode(RTC_RCU, RTC_GPIO, RTC_DATA_PIN, GPIO_OSPEED_50MHZ, GPIO_AF_5);
/* SPI_SCK pf7 */
gpio_init_af_mode(RTC_RCU, RTC_GPIO, RTC_SCK_PIN, GPIO_OSPEED_50MHZ, GPIO_AF_5);
/* RTC CE */
gpio_init_output_mode(RTC_RCU, RTC_GPIO, RTC_CE_PIN, GPIO_OSPEED_50MHZ, 0);
CE_LOW;
/* SPI parameter config */
spi_init_struct.trans_mode = SPI_TRANSMODE_BDTRANSMIT;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_64;
spi_init_struct.endian = SPI_ENDIAN_LSB;
spi_init(CURRENT_SPI, &spi_init_struct);
/* enable */
spi_enable(CURRENT_SPI);
}
static void spi_rtc_send_byte(uint8_t byte)
{
/* loop while data register in not empty */
while(RESET == spi_i2s_flag_get(CURRENT_SPI, SPI_FLAG_TBE));
/* send byte through the SPI peripheral */
spi_i2s_data_transmit(CURRENT_SPI, byte);
while(spi_i2s_flag_get(CURRENT_SPI, SPI_FLAG_TRANS));
}
static void write_ds1302(uint8_t address, uint8_t data)
{
WRITE_MODE;
CE_HIGH;
spi_rtc_send_byte(address);
spi_rtc_send_byte(data);
CE_LOW;
}
static uint8_t read_ds1302(uint8_t address)
{
uint8_t data;
/* send addr */
WRITE_MODE;
CE_HIGH;
spi_rtc_send_byte(address);
/* recive data */
READ_MODE;
while(RESET == spi_i2s_flag_get(CURRENT_SPI, SPI_FLAG_RBNE));
CE_LOW;
WRITE_MODE;
data = spi_i2s_data_receive(CURRENT_SPI);
while(spi_i2s_flag_get(CURRENT_SPI, SPI_FLAG_TRANS));
return data;
}
#else
void spi5_init() {
gpio_init_output_mode(RTC_RCU, RTC_GPIO, RTC_SCK_PIN, GPIO_OSPEED_2MHZ, 0);
gpio_init_output_mode(RTC_RCU, RTC_GPIO, RTC_DATA_PIN, GPIO_OSPEED_2MHZ, 0);
gpio_init_output_mode(RTC_RCU, RTC_GPIO, RTC_CE_PIN, GPIO_OSPEED_50MHZ, 0);
}
static void rtc_delay(int count) {
while (count) {
count--;
}
}
static void spi_rtc_send_byte(uint8_t value)
{
uint8_t index;
WRITE_MODE;
for (index = 0; index < 8; index++)
{
CLK_LOW;
if (value&0x01)
{
DATA_HIGH;
}
else
{
DATA_LOW;
}
rtc_delay(1);
CLK_HIGH;
rtc_delay(1);
value >>= 1;
}
//CLK_LOW;
}
static void spi_rtc_recive_byte(u8 *value) {
uint8_t index;
READ_MODE;
for (index = 0; index < 8; index++)
{
*value >>= 1;
CLK_HIGH;
rtc_delay(1);
CLK_LOW;
rtc_delay(1);
if (DATA == 1) {
*value |= 0x80;
} else {
*value &= 0x7F;
}
}
}
static void write_ds1302(uint8_t address, uint8_t data)
{
CLK_LOW;
CE_HIGH;
spi_rtc_send_byte(address);
spi_rtc_send_byte(data);
CLK_LOW;
CE_LOW;
}
static uint8_t read_ds1302(uint8_t address)
{
uint8_t data = 0;
CLK_LOW;
CE_HIGH;
spi_rtc_send_byte(address);
spi_rtc_recive_byte(&data);
CE_LOW;
return data;
}
#endif
STM32代码:
#include "io.h"
#include "io_stm32.h"
#include "common.h"
//#define DS1302_USING_SPI
/* PA5-SCK PA6-CE PA7-DATA */
#define CURRENT_SPI SPI1
#define RTC_RCC RCC_APB2Periph_GPIOA
#define RTC_GPIO GPIOA
#define RTC_SCK_PIN GPIO_Pin_5
#define RTC_CE_PIN GPIO_Pin_6
#define RTC_DATA_PIN GPIO_Pin_7
#ifdef DS1302_USING_SPI
#define READ_MODE SPI_Cmd(CURRENT_SPI, DISABLE); \
SPI_BiDirectionalLineConfig(CURRENT_SPI, SPI_Direction_Rx); \
SPI_Cmd(CURRENT_SPI, ENABLE);
#define WRITE_MODE SPI_Cmd(CURRENT_SPI, DISABLE); \
SPI_BiDirectionalLineConfig(CURRENT_SPI, SPI_Direction_Tx); \
SPI_Cmd(CURRENT_SPI, ENABLE);
#define CE_HIGH GPIO_SetBits(RTC_GPIO, RTC_CE_PIN);
#define CE_LOW GPIO_ResetBits(RTC_GPIO, RTC_CE_PIN);
#else
#define READ_MODE gpio_init(RTC_RCC, RTC_GPIO, GPIO_Mode_IPU, GPIO_Speed_50MHz, RTC_DATA_PIN);
#define WRITE_MODE gpio_init(RTC_RCC, RTC_GPIO, GPIO_Mode_Out_PP, GPIO_Speed_50MHz, RTC_DATA_PIN);
#define CE_HIGH GPIO_SetBits(RTC_GPIO, RTC_CE_PIN);
#define CE_LOW GPIO_ResetBits(RTC_GPIO, RTC_CE_PIN);
#define CLK_HIGH GPIO_SetBits(RTC_GPIO, RTC_SCK_PIN);
#define CLK_LOW GPIO_ResetBits(RTC_GPIO, RTC_SCK_PIN);
#define DATA_HIGH GPIO_SetBits(RTC_GPIO, RTC_DATA_PIN);
#define DATA_LOW GPIO_ResetBits(RTC_GPIO, RTC_DATA_PIN);
#define DATA GPIO_ReadInputDataBit(RTC_GPIO, RTC_DATA_PIN)
#endif
#define WRITE_FLAG_ADDR 0xC0
#define READ_FLAG_ADDR 0xC1
#define RTC_INIT_FLAG 0x35
#define YEAR_BASE 2021
/* 默认起始时间2021年1月1日,星期五 */
time_t init_time = {YEAR_BASE, 1, 1, 1, 0, 0, 5};
void spi5_init(void){}
#ifdef DS1302_USING_SPI
void spi1_init(void)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_I2S_DeInit(CURRENT_SPI);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/* SPI_MOSI PA7 */
gpio_init(RTC_RCC, RTC_GPIO, GPIO_Mode_AF_PP, GPIO_Speed_50MHz, RTC_DATA_PIN);
/* SPI_SCK PA5 */
gpio_init(RTC_RCC, RTC_GPIO, GPIO_Mode_AF_PP, GPIO_Speed_50MHz, RTC_SCK_PIN);
/* RTC CE */
gpio_init(RTC_RCC, RTC_GPIO, GPIO_Mode_Out_PP, GPIO_Speed_50MHz, RTC_CE_PIN);
CE_LOW;
/* SPI parameter config */
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(CURRENT_SPI, &SPI_InitStructure);
SPI_Cmd(CURRENT_SPI, ENABLE);
}
static void spi_rtc_send_byte(uint8_t byte)
{
/* loop while data register in not empty */
while(RESET == SPI_I2S_GetFlagStatus(CURRENT_SPI, SPI_I2S_FLAG_TXE));
/* send byte through the SPI peripheral */
SPI_I2S_SendData(CURRENT_SPI, byte);
while(SPI_I2S_GetFlagStatus(CURRENT_SPI, SPI_I2S_FLAG_BSY));
}
static void write_ds1302(uint8_t address, uint8_t data)
{
WRITE_MODE;
CE_HIGH;
spi_rtc_send_byte(address);
spi_rtc_send_byte(data);
CE_LOW;
}
static uint8_t read_ds1302(uint8_t address)
{
uint8_t data;
/* send addr */
WRITE_MODE;
CE_HIGH;
spi_rtc_send_byte(address);
/* recive data */
READ_MODE;
while(RESET == SPI_I2S_GetFlagStatus(CURRENT_SPI, SPI_I2S_FLAG_RXNE));
CE_LOW;
WRITE_MODE;
data = SPI_I2S_ReceiveData(CURRENT_SPI);
while(SPI_I2S_GetFlagStatus(CURRENT_SPI, SPI_I2S_FLAG_BSY));
return data;
}
#else
void spi1_init() {
gpio_init(RTC_RCC, RTC_GPIO, GPIO_Mode_Out_PP, GPIO_Speed_50MHz, RTC_DATA_PIN);
gpio_init(RTC_RCC, RTC_GPIO, GPIO_Mode_Out_PP, GPIO_Speed_50MHz, RTC_CE_PIN);
gpio_init(RTC_RCC, RTC_GPIO, GPIO_Mode_Out_PP, GPIO_Speed_50MHz, RTC_SCK_PIN);
GPIO_ResetBits(RTC_GPIO, RTC_DATA_PIN | RTC_SCK_PIN | RTC_CE_PIN);
}
static void rtc_delay(int count) {
while (count) {
count--;
}
}
static void spi_rtc_send_byte(uint8_t value)
{
uint8_t index;
WRITE_MODE;
for (index = 0; index < 8; index++)
{
CLK_LOW;
if (value&0x01)
{
DATA_HIGH;
}
else
{
DATA_LOW;
}
rtc_delay(1);
CLK_HIGH;
rtc_delay(1);
value >>= 1;
}
}
static void spi_rtc_receive_byte(u8 *value) {
uint8_t index;
READ_MODE;
for (index = 0; index < 8; index++)
{
*value >>= 1;
CLK_HIGH;
rtc_delay(1);
CLK_LOW;
rtc_delay(1);
if (DATA == 1) {
*value |= 0x80;
} else {
*value &= 0x7F;
}
}
}
static void write_ds1302(uint8_t address, uint8_t data)
{
CLK_LOW;
CE_HIGH;
spi_rtc_send_byte(address);
spi_rtc_send_byte(data);
CLK_LOW;
CE_LOW;
}
static uint8_t read_ds1302(uint8_t address)
{
uint8_t data = 0;
CLK_LOW;
CE_HIGH;
spi_rtc_send_byte(address);
spi_rtc_receive_byte(&data);
CE_LOW;
return data;
}
#endif
对外接口代码:
#define DS1302_UNLOCK write_ds1302(0x8e, 0x00);
#define DS1302_LOCK write_ds1302(0x8e, 0x80);
void rtc_time_init(void)
{
uint8_t hour;
uint8_t hour_24 = 0;
if (read_ds1302(READ_FLAG_ADDR) != RTC_INIT_FLAG)
{
write_ds1302(0x84, hour_24);
set_rtc(init_time);
return;
}
hour = read_ds1302(0x85);
if (hour > 0x80)
{
// 12小时制转为24小时制
hour_24 = (hour > 0xA0)?(hour&0x1F)|DEC2BCD(12):(hour&0x1F);
write_ds1302(0x84, hour_24);
}
}
void set_rtc(time_t t)
{
uint8_t year = t.year - YEAR_BASE;
if(year >= 100) year = 0;
DS1302_UNLOCK;
/* 写入已经设置时间标记 */
write_ds1302(WRITE_FLAG_ADDR, RTC_INIT_FLAG);
write_ds1302(0x80, DEC2BCD(t.second));
write_ds1302(0x82, DEC2BCD(t.minute));
write_ds1302(0x84, DEC2BCD(t.hour));
write_ds1302(0x86, DEC2BCD(t.day));
write_ds1302(0x88, DEC2BCD(t.month));
write_ds1302(0x8c, DEC2BCD(year));
write_ds1302(0x8a, DEC2BCD(t.week));
DS1302_LOCK;
}
time_t get_rtc(void)
{
time_t t;
uint16_t year = read_ds1302(0x8d);
uint8_t month = read_ds1302(0x89);
uint8_t day = read_ds1302(0x87);
uint8_t hour = read_ds1302(0x85);
uint8_t minute = read_ds1302(0x83);
uint8_t second = read_ds1302(0x81);
uint8_t week = read_ds1302(0x8b);
t.year = BCD2DEC(year) + YEAR_BASE;
t.month = BCD2DEC(month);
t.day = BCD2DEC(day);
t.hour = BCD2DEC(hour);
t.minute = BCD2DEC(minute);
t.second = BCD2DEC(second);
t.week = BCD2DEC(week);
return t;
}
例行结果展示
串口打印时间
![ab9e42b22c7db8853b605af5f437d7c4.gif](https://img-blog.csdnimg.cn/img_convert/ab9e42b22c7db8853b605af5f437d7c4.gif)
GD32 SPI驱动DS1302 示波器数据
![ca21d04c5ad5f97a257a1d6a8576b4d4.png](https://img-blog.csdnimg.cn/img_convert/ca21d04c5ad5f97a257a1d6a8576b4d4.png)
![88f21cf351a3258945295a88bc200a36.png](https://img-blog.csdnimg.cn/img_convert/88f21cf351a3258945295a88bc200a36.png)
GD32 IO口模拟驱动DS1302 示波器数据
![2fff08c23d1e5fc7761f3300928b7bf2.png](https://img-blog.csdnimg.cn/img_convert/2fff08c23d1e5fc7761f3300928b7bf2.png)
![5d166d272cb8ac8ff640dd6cfd56af3f.png](https://img-blog.csdnimg.cn/img_convert/5d166d272cb8ac8ff640dd6cfd56af3f.png)
STM32 SPI驱动DS1302 示波器数据
![f4142c490b0175fb58e514d2ae99bb07.png](https://img-blog.csdnimg.cn/img_convert/f4142c490b0175fb58e514d2ae99bb07.png)
![805090546f130bb91e6adbf7cd5a966b.png](https://img-blog.csdnimg.cn/img_convert/805090546f130bb91e6adbf7cd5a966b.png)
STM32 IO口模拟驱动DS1302 示波器数据
![628517f90b0b92ade4dca100cd0e36e7.png](https://img-blog.csdnimg.cn/img_convert/628517f90b0b92ade4dca100cd0e36e7.png)
![2575493ceace3b644b08c821bb405bae.png](https://img-blog.csdnimg.cn/img_convert/2575493ceace3b644b08c821bb405bae.png)
--EOF--
例行求粉,谢谢!
![091755efc847c00172e71beb92b4b215.png](https://img-blog.csdnimg.cn/img_convert/091755efc847c00172e71beb92b4b215.png)