江协科技51单片机学习- p23 DS1302实时时钟

news/2024/7/8 10:42:11 标签: 科技, 51单片机, 学习

🚀write in front🚀  
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​ 

💬本系列哔哩哔哩江科大51单片机的视频为主以及自己的总结梳理📚 

前言:

本文是根据哔哩哔哩网站上“江协科技51单片机”视频的学习笔记,在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了江协科技51单片机教学视频和链接中的内容。

引用:

51单片机入门教程-2020版 程序全程纯手打 从零开始入门_哔哩哔哩_bilibili

​​​​​​c51语言变量语句意思,C51中循环语句-CSDN博客

DS1302引用:

DS1302时钟 ---- 自学笔记_ds1302时寄存器地址-CSDN博客

DS1302(实时时钟芯片)_keil5ds1302-CSDN博客

DS1302实时时钟-CSDN博客

DS1302时钟(实现时钟案例)_ds1302实现实时时钟的程序设计流程-CSDN博客

正文:

0. 🌿概述

在淘宝上购买了江协科技51单片机开发板套件(普中科技STC51单片机A2型号),就上在上一篇博文里说的自己计划学习下江协科技51单片机开发教程,通过STC51单片机这种MCU这种贴近于裸机的开发来增加对于系统硬件层面知识的了解和掌握。

术语和缩略语:

缩写全称说明
RTCReal Time Clock实时时钟

1. 🚀DS1302实时时钟芯片

DS1302实时时钟芯片引脚定义如下

引脚描述
VCC2双供电配置中的主电源供应管脚
VCC1 VCC1 连接到备用电源,在主电源失效时保持时间和日期数据
X1接外部晶振 32.768KHz
X2接外部晶振 32.768KHz
GND接地
SCLK串行时钟
I/O输出输出
CE使能控制位

🍎CE使能位控制对DS1302时间寄存器的读写,当CE=0时对寄存器的读写无效。注意CE为并不影响DS1302的计时部分,计时CE=0 DS1602的计时部分也会正常计时。

DS1302内部模块框图

DS1302命令字:

  • MSB7:第7位必须为1
  • MSB6:第6位为0时表示实时时钟数据,为1表示内部RAM数据。
  • MSB5~MSB1:共5位表示寄存器地址
  • MSB0:第0位为0表示写,为1表示读。

DS1302单字节读/写时序:

  • 🧃单字节读指令时序:
     🐳 CE为1高电平,使能DS1302读写。
     🐳 SCLK串行时钟每次上升沿,I/O口上的数据一位移动到DS1302的移位寄存器中,I/O发送数据时先发送LSB最低位。SCLK 经过8个时钟上升沿之后,DS1302命令字传输完成。
    🐳  接下来,在SCLK的时钟下降沿DS1302将命令字中要读取的指定地址的寄存器内容的一位送到I/O,SCLK每一次时钟下降沿指定要读取寄存器的下一位输出到I/O,经过8个时钟下降沿之后,要读取指定地址的寄存器里的值输出完成。DS1302寄存器读取时LSB先输出。

  • 🧃单字节写指令时序:
    🐳 CE为1高电平,使能DS1302读写。
    🐳 SCLK串行时钟每次上升沿,I/O口上的数据一位移动到DS1302的移位寄存器中,I/O发送数据时先发送LSB最低位。SCLK 经过8个时钟上升沿之后,DS1302命令字传输完成。
    🐳  接下来,要写入的数据的D0位写到I/O,SCLK串行时钟每次上升沿,I/O口上的数据一位移动到DS1302的移位寄存器中,SCLK 经过8个时钟上升沿之后要写入的数据 D0~D7写入到寄存器完成。

注意:

😎,SCLK时钟一直是由单片机控制输出的,DS1302按照SCLK时钟的时序从I/O口读取数据到移位寄存器,或者从移位寄存器输出数据到I/O口。

DS1302的寄存器地址定义

2. 🚀开发板DS1302电路原理图

3. 隔一次读取DSS1302数据错误问题

 注意其中一个关键问题:

https://bbs.csdn.net/topics/390207271

🥸上面引用链接里的读取 DS1302 时钟的问题现象和我自己实验测试遇到的问题一样,每隔一次读取出来的值是正确,然后下一次读取出来的值是 0xFF,再一次读取出来的值正确,再下一次读取出来值是 0xFF。😰

😰问题的原因到处找没有找到详细的解释,只是可以找到解决这个问题的方法,就是如在江协科技视频教程里所讲在读取DS1302的值之后,手动将 DS1302_IO=0 置为低电平,这样可以解决问题,但是为什么不这样做就会每隔一次读取出来错误的值还是在网上资料里没有找到详细的解释予原因。

😰,在网上的51单片机DS1302的其它学习资料,例如,蓝桥杯51 DS1302 或者是普中科技51 DS1302的教程里,在读取DS1302的数据之后附加了一段代码来对DS1302进行复位,来解决读取DS1302读取到错误值的问题。

/**
  * @brief  
  * @param  
  * @retval 
  */
unsigned char DS1302_ReadByte(unsigned char Command)
{
	unsigned char i = 0;
	unsigned char Data = 0;
	
	DS1302_CE = 1;
	
	for(i=0; i<8; i++)
	{
		DS1302_IO = Command & (0x01 << i);
		DS1302_SCLK	= 0;
		DS1302_SCLK = 1;
	}
	
	
	/* 为什么需要这一句??*/
	//DS1302_IO = 0;
	
	for(i=0; i<8; i++)
	{
		DS1302_SCLK = 1;	
		DS1302_SCLK	= 0;
		if(DS1302_IO)
		{
			Data |= (0x01 << i);
		}
	}

	/* 为什么需要这一句??*/
	DS1302_IO = 0;			//加上这一句否则会随机读取出错误值
	
	DS1302_CE = 0;
	
	return Data;
}

4. DS1302读取年月日小时分钟

DS1302读取年月日小时分钟,DS1302 年,月,日,小时,分钟,秒 寄存器里存放的并不是10进制或者16进制的数据,在DS1302 年月日小时分钟寄存器里存放的是 BCD 码(Binary Coded Decimal),寄存器长度为8位,高4位存放10进制数的十位,低4为存放10进制数的个位。

🚗 我们需要将DS1302 年月日寄存器里存放的 BCD 编码格式的值转换为10进制格式的值。

🚗 转换方法为:

     十进制数 = (BCD/16)*10 + (BCD%16)

      BCD数 = (十进制数/10)*16 + (十进制数%10)

5. DS1302综合源码编写

🚀 本次实验将综合运用之前练习过得单片机实验内容做一个综合性和使用按键可以调节的DS1302时钟,所使用到的之间的知识点有:

所以本次实验的源码文件比较多:

main.c 

#include <REGX52.H>
#include <INTRINS.H>
#include "delay.h"
#include "DS1302.h"
#include "LCD1602.h"
#include "Key.h"
#include "Timer0.h"
#include "UART.H"

unsigned char KeyNum = 0;
unsigned char Mode = 0;
unsigned char TimeSetSelect = 0;
unsigned char TimeFlashFlag = 0;
	
void TimeShow(void)
{
	DS1302_ReadTime();
	
	LCD_ShowString(1, 1, "  -  -");
	LCD_ShowNum(1, 1, DS1302_Time[0], 2);
	LCD_ShowNum(1, 4, DS1302_Time[1], 2);
	LCD_ShowNum(1, 7, DS1302_Time[2], 2);


	LCD_ShowString(2, 1, "  :  :");
	LCD_ShowNum(2, 1, DS1302_Time[3], 2);
	LCD_ShowNum(2, 4, DS1302_Time[4], 2);
	LCD_ShowNum(2, 7, DS1302_Time[5], 2);
	

}

void TimeSet(void)
{
	if(KeyNum == 2)
	{
		TimeSetSelect++;
		TimeSetSelect %= 6;
	}
	else if(KeyNum == 3)
	{
		DS1302_Time[TimeSetSelect]++;
		
		if(DS1302_Time[0] > 99) { DS1302_Time[0] = 0;}
		if(DS1302_Time[1] > 12) { DS1302_Time[1] = 1;}
		
		if(DS1302_Time[1] == 1 || DS1302_Time[1] == 3 || DS1302_Time[1] == 5 || DS1302_Time[1] == 7 
			|| DS1302_Time[1] == 8 || DS1302_Time[1] == 10 ||  DS1302_Time[1] == 12)
		{
			if(DS1302_Time[2] > 31) { DS1302_Time[2] = 1;}
		}
		else if(DS1302_Time[1] == 4 || DS1302_Time[1] == 6 || DS1302_Time[1] == 9 || DS1302_Time[1] == 11)
		{
			if(DS1302_Time[2] > 30) { DS1302_Time[2] = 1;}
		}
		else if(DS1302_Time[1] == 2)
		{
			if((DS1302_Time[0] % 4) == 0)
				if(DS1302_Time[2] > 29) { DS1302_Time[2] = 1;}
			else
				if(DS1302_Time[2] > 29) { DS1302_Time[2] = 1;}
		}
		
		if(DS1302_Time[3] > 23) { DS1302_Time[3] = 0;}
		if(DS1302_Time[4] > 59) { DS1302_Time[4] = 0;}
		if(DS1302_Time[5] > 59) { DS1302_Time[5] = 0;}
	}
	else if(KeyNum == 4)
	{
		DS1302_Time[TimeSetSelect]--;
		
		
		if(DS1302_Time[0] < 0) { DS1302_Time[0] = 99;}
		if(DS1302_Time[1] < 1) { DS1302_Time[1] = 12;}
		
		if(DS1302_Time[1] == 1 || DS1302_Time[1] == 3 || DS1302_Time[1] == 5 || DS1302_Time[1] == 7 
			|| DS1302_Time[1] == 8 || DS1302_Time[1] == 10 ||  DS1302_Time[1] == 12)
		{
			if(DS1302_Time[2] < 1) { DS1302_Time[2] = 31;}
			if(DS1302_Time[2] > 31) { DS1302_Time[2] = 1;}
			
		}
		else if(DS1302_Time[1] == 4 || DS1302_Time[1] == 6 || DS1302_Time[1] == 9 || DS1302_Time[1] == 11)
		{
			if(DS1302_Time[2] < 1) { DS1302_Time[2] = 30;}
			if(DS1302_Time[2] > 30) { DS1302_Time[2] = 1;}
		}
		else if(DS1302_Time[1] == 2)
		{
			if((DS1302_Time[0] % 4) == 0){
				if(DS1302_Time[2] < 1) { DS1302_Time[2] = 29;}
				if(DS1302_Time[2] > 29) { DS1302_Time[2] = 1;}
			}
			else{
				if(DS1302_Time[2] < 1) { DS1302_Time[2] = 28;}
				if(DS1302_Time[2] > 28) { DS1302_Time[2] = 1;}
			}
		}
		
		if(DS1302_Time[3] < 0) { DS1302_Time[3] = 23;}
		if(DS1302_Time[4] < 0) { DS1302_Time[4] = 59;}
		if(DS1302_Time[5] < 0) { DS1302_Time[5] = 59;}
	}
	
	
	//if(KeyNum)
	{
		if(TimeSetSelect==0 && TimeFlashFlag==1)
		{
			LCD_ShowString(1, 1, "  ");
		}
		else{
			LCD_ShowNum(1, 1, DS1302_Time[0], 2);
		}

		if(TimeSetSelect==1 && TimeFlashFlag==1)
		{
			LCD_ShowString(1, 4, "  ");
		}
		else{
			LCD_ShowNum(1, 4, DS1302_Time[1], 2);
		}

		if(TimeSetSelect==2 && TimeFlashFlag==1)
		{
			LCD_ShowString(1, 7, "  ");
		}
		else{
			LCD_ShowNum(1, 7, DS1302_Time[2], 2);
		}

		if(TimeSetSelect==3 && TimeFlashFlag==1)
		{
			LCD_ShowString(2, 1, "  ");
		}
		else{
			LCD_ShowNum(2, 1, DS1302_Time[3], 2);
		}

		if(TimeSetSelect==4 && TimeFlashFlag==1)
		{
			LCD_ShowString(2, 4, "  ");
		}
		else{
			LCD_ShowNum(2, 4, DS1302_Time[4], 2);
		}

		if(TimeSetSelect==5 && TimeFlashFlag==1)
		{
			LCD_ShowString(2, 7, "  ");
		}
		else{
			LCD_ShowNum(2, 7, DS1302_Time[5], 2);
		}

		LCD_ShowNum(2, 13, TimeFlashFlag, 1);
		if(KeyNum)
			LCD_ShowNum(2, 10, KeyNum, 1);
	}	
}

void main()
{
	DS1302_Init();
	LCD_Init();
	Timer0_Init();
	
	DS1302_SetTime();
	
	while(1)
	{
		KeyNum = Key();
		if(KeyNum)
		{
			if(KeyNum == 1)
			{
				if(Mode == 0) {Mode=1; }
				else if(Mode == 1)
				{	Mode=0; 
					DS1302_SetTime();
					TimeSetSelect = 0;
				}
				
			}			
		}
		
		switch(Mode)
		{
			case 0: TimeShow(); break;
			case 1: TimeSet();  break;
		}
		
		//Delay(1000);
	}
}


/**
  * @brief  定时器0中断处理函数模版
  * @param  无
  * @retval 无
  */
void Timer_Routine(void) interrupt 1
{
	static unsigned int count = 0;
	
	count++;
	if(count >= 500)		//定时器T0每1ms中断一次,进入1000次经过了1s
	{
		TimeFlashFlag = !TimeFlashFlag;
		count = 0;
	}
	
	//定时器溢出之后需要重新装载
	TH0 = (65535 - 1000) / 256;					//12MHz晶振,12分频
	TL0 = (65535 - 1000) % 256 + 1; 			//
}

DS1302.c 

#include "DS1302.h"
#include "Delay.h"


char DS1302_Time [] = {24, 7, 2, 22, 35, 2, 2};



#define DS1302_SECOND 	0x80
#define DS1302_MINUTE 	0x82
#define DS1302_HOUR 	0x84
#define DS1302_DATE 	0x86
#define DS1302_MONTH 	0x88
#define DS1302_DAY 		0x8A
#define DS1302_YEAR 	0x8C
#define DS1302_WP 		0x8E

/**
  * @brief  
  * @param  
  * @retval 
  */
void DS1302_Init(void)
{
	DS1302_CE = 0;
	DS1302_SCLK = 0;
}

/**
  * @brief  
  * @param  
  * @retval 
  */
void DS1302_WriteByte(unsigned char Command, unsigned char Data)
{
	unsigned char i = 0;
	
	DS1302_CE = 1;
	
	
	for(i=0; i<8; i++)
	{
		DS1302_IO = Command & (0x01 << i);
		DS1302_SCLK = 1;
		51单片机的速度比较慢,不需要延时
		DS1302_SCLK	= 0;
	}

	for(i=0; i<8; i++)
	{
		DS1302_IO = Data & (0x01 << i);
		DS1302_SCLK = 1;
		DS1302_SCLK	= 0;
	}
	
	DS1302_CE = 0;
}


/**
  * @brief  
  * @param  
  * @retval 
  */
unsigned char DS1302_ReadByte(unsigned char Command)
{
	unsigned char i = 0;
	unsigned char Data = 0;
	
	DS1302_CE = 1;
	
	
	Command |= 0x01;
	for(i=0; i<8; i++)
	{
		DS1302_IO = Command & (0x01 << i);
		DS1302_SCLK	= 0;
		DS1302_SCLK = 1;
	}
	
	
	/* 为什么需要这一句??*/
	//DS1302_IO = 0;
	
	for(i=0; i<8; i++)
	{
		DS1302_SCLK = 1;	
		DS1302_SCLK	= 0;
		if(DS1302_IO)
		{
			Data |= (0x01 << i);
		}
	}

	/* 为什么需要这一句??*/
	DS1302_IO = 0;			//加上这一句否则会随机读取出错误值
	
	DS1302_CE = 0;
	
	return Data;
}

/**
  * @brief  
  * @param  
  * @retval 
  */
void DS1302_SetTime(void)
{
	//关闭DS1302写保护
	DS1302_WriteByte(DS1302_WP, 0x00);
	
	
	DS1302_WriteByte(DS1302_YEAR, 	DS1302_Time[0]/10*16 + DS1302_Time[0]%10);
	DS1302_WriteByte(DS1302_MONTH, 	DS1302_Time[1]/10*16 + DS1302_Time[1]%10);
	DS1302_WriteByte(DS1302_DATE, 	DS1302_Time[2]/10*16 + DS1302_Time[2]%10);
	DS1302_WriteByte(DS1302_HOUR, 	DS1302_Time[3]/10*16 + DS1302_Time[3]%10);
	DS1302_WriteByte(DS1302_MINUTE, DS1302_Time[4]/10*16 + DS1302_Time[4]%10);
	DS1302_WriteByte(DS1302_SECOND, DS1302_Time[5]/10*16 + DS1302_Time[5]%10);
	DS1302_WriteByte(DS1302_DAY, 	DS1302_Time[6]/10*16 + DS1302_Time[6]%10);
	
	
	//打开DS1302写保护
	//DS1302_WriteByte(DS1302_WP, 0x80);
}

/**
  * @brief  
  * @param  
  * @retval 
  */
void DS1302_ReadTime(void)
{
	unsigned char temp;
	temp = DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0] = temp/16*10 + temp%16;
	
	temp = DS1302_ReadByte(DS1302_MONTH);
	DS1302_Time[1] = temp/16*10 + temp%16;
	
	temp = DS1302_ReadByte(DS1302_DATE);
	DS1302_Time[2] = temp/16*10 + temp%16;
	
	temp = DS1302_ReadByte(DS1302_HOUR);
	DS1302_Time[3] = temp/16*10 + temp%16;
	
	temp = DS1302_ReadByte(DS1302_MINUTE);
	DS1302_Time[4] = temp/16*10 + temp%16;
	
	temp = DS1302_ReadByte(DS1302_SECOND);
	DS1302_Time[5] = temp/16*10 + temp%16;
	
	temp = DS1302_ReadByte(DS1302_DAY);
	DS1302_Time[6] = temp/16*10 + temp%16;
}

DS1302.h

#ifndef __DS1302_H__
#define __DS1302_H__

#include <REGX52.H>


sbit DS1302_SCLK = P3^6;
sbit DS1302_CE = P3^5;
sbit DS1302_IO = P3^4;

extern char DS1302_Time [];


void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command, unsigned char Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_ReadTime(void);
void DS1302_SetTime(void);

#endif

Key.c 

#include <REGX52.H>
#include "key.h"
#include "delay.h"

/**
  * @brief  获取独立按键键码
  * @param  无
  * @retval 按下按键的键码,范围0~4,无按键按下时返回0
  */
unsigned char Key(void)
{
	unsigned char keyNumber = 0;
	
	if(P3_1 == 0){
		Delay(10);				//按键按下消抖
		while(P3_1 == 0);		//检测松手,没有松手一直循环
		Delay(10);				//按键松开消抖
		keyNumber = 1;
	}
	
	if(P3_0 == 0){
		Delay(10);				//按键按下消抖
		while(P3_0 == 0);		//检测松手,没有松手一直循环
		Delay(10);				//按键松开消抖
		
		keyNumber = 2;
	}
		
	if(P3_2 == 0){
		Delay(10);				//按键按下消抖
		while(P3_2 == 0);		//检测松手,没有松手一直循环
		Delay(10);				//按键松开消抖
		
		keyNumber = 3;
	}
		
	if(P3_3 == 0){
		Delay(10);				//按键按下消抖
		while(P3_3 == 0);		//检测松手,没有松手一直循环
		Delay(10);				//按键松开消抖
		
		keyNumber = 4;
	}
	
	return keyNumber;
}

Key.h 

#ifndef __KEY_H__
#define __KEY_H__

unsigned char Key(void);

#endif

Timer0.c

#include <REGX52.H>
#include "timer0.h"

/**
  * @brief  定时器0初始化函数, 1ms 12MHz
  * @param  无
  * @retval 无
  */
void Timer0_Init()
{
	
	//AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;			//设置定时初值
	TH0 = 0xFC;			//设置定时初值
	TF0 = 0;			//清除TF0标志
	TR0 = 1;			//定时器0开始计时
	
	
	//中断部分寄存器
	ET0 = 1;			//允许定时器T0中断
	EA = 1;				//允许中断
	PT0 = 0;			//定时器T0中断优先级
}

/**
  * @brief  定时器0中断处理函数模版
  * @param  无
  * @retval 无
  */
//void Timer_Routine(void) interrupt 1
//{
//	static unsigned int count = 0;
//	
//	count++;
//	//P2_0 = 0;
//	if(count >= 500)		//定时器T0每1ms中断一次,进入1000次经过了1s
//	{
//		P2_0 = ~P2_0;
//		count = 0;
//	}
//	
//	//定时器溢出之后需要重新装载
//	TH0 = (65535 - 1000) / 256;					//12MHz晶振,12分频
//	TL0 = (65535 - 1000) % 256 + 1; 			//
//}

Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init();
void Timer_Routine(void);

#endif

6. 实验总结

🌵51单片机 DS1302实时时钟芯片实验需要注意的点是:

  1. 🐟️ 对DS1302注意开启写保护
  2. 🐟️ 对DS1302进行读取时,在读取的最后一步需要将 DS1302_IO=0,否则会读取到0xFF值。在其它的51单片机DS1302实验的教程里都有提到这一点需要再读取DS1302寄存器的最有将 DS1302_IO=0引脚拉低。


http://www.niftyadmin.cn/n/5537129.html

相关文章

大数据基础知识【大数据导论】

各位大佬好 &#xff0c;这里是阿川的博客&#xff0c;祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 大数据基础知识前 必看 【大数据导论】—大数据序言…

从我邮毕业啦!!!

引言 时间过的好快&#xff0c;转眼间就要从北邮毕业了&#xff0c;距离上一次月度总结又过去了两个月&#xff0c;故作本次总结。 PS: https://github.com/WeiXiao-Hyy/blog整理了后端开发的知识网络&#xff0c;欢迎Star&#xff01; 毕业&#x1f393; 6月1号完成了自己的…

sqlserver 修改库 取消大小写,无视别的线程使用

将数据库设置为单用户模式&#xff0c;然后再次尝试修改排序规则: 避免修改失败&#xff01; USE master; ALTER DATABASE 数据库名称SET SINGLE_USER WITH ROLLBACK IMMEDIATE; ALTER DATABASE 数据库名称COLLATE Chinese_PRC_CI_AS; ALTER DATABASE 数据库名称SET MULTI_USE…

MViT(ICCV 2021, Meta)论文解读

paper&#xff1a;Multiscale Vision Transformers official implementation&#xff1a;https://github.com/facebookresearch/SlowFast 背景和出发点 这篇文章提出了多尺度视觉Transformer&#xff08;Multiscale Vision Transformers, MViT&#xff09;的概念&#xff0c…

SQLite 附加数据库

SQLite 附加数据库 SQLite 是一种轻量级的数据库管理系统,因其小巧、快速和易于使用而广受欢迎。在 SQLite 中,可以将多个数据库文件附加到单个数据库连接中,从而允许用户在不同的数据库之间轻松切换和操作数据。本文将详细介绍如何在 SQLite 中附加数据库,并探讨其使用场…

如何在 Odoo 16 网站中创建通用控制器

在Odoo中,通常网站表单允许用户输入数据,提交后会调用相应的控制器,并在控制器指定的模型中创建记录。 在这篇博客中,我们将创建一个通用控制器,可用于在提交表单时在任何模型中创建记录。 1. 首先,我们必须创建一个带有输入字段的网站表单。 <template id="ge…

flask项目部署总结

这个部署的时候要用虚拟环境&#xff0c;cd进项目文件夹 python3 -m venv myenv source myenv/bin/activate激活 之后就安装一些库包之类的&#xff0c;&#xff08;flask&#xff0c;requests,bs4,等等&#xff09; 最重要的是要写.flaskenv文件并且pip install 一个能运行…

将带有 商店idr 商品信息的json导入到mongodb后,能不能根据商店id把所有商品全部提取并转为电子表格

当您已经将包含商店ID&#xff08;如realMallId&#xff09;的商品信息导入MongoDB后&#xff0c;确实可以轻松地根据商店ID提取所有相关商品信息并转换为电子表格&#xff08;例如Excel&#xff09;。这里是一个简化的流程&#xff0c;使用Python的pymongo库来查询MongoDB&…