KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记10 - STM32的SDIO学习2

KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记10 - STM32的SDIO学习2

  • 一、问题回顾
  • 二、本次的任务
  • 三、 需要注意的问题
    • 3.1 Card Identification Mode时的时钟频率
    • 3.2 CMD0指令的疑似问题
    • 3.3 发送带参数的ACMD41时要注意时间时序和时效
    • 3.4 CPSM的指令发送问题
    • 3.5 调试过程中的SD卡的状态
  • 四、代码设计
  • 五、测试结果
  • 六、结论

一、问题回顾

根据上一篇中介绍的思路,我尝试调试了几次。笔者又发现了以下的问题:

问题原因解决
调试的时候如果一直插着卡,或者不将卡拔出而上电复位开发板再进入调试,会发现卡无法初始化开发板在上电的时候就会执行先前残留的程序。如果这部分程序中包含了初始化卡的代码,则会把卡初始化。当进入DEBUG后,卡已经处于DATA_TRANSFER状态,不再响应CMD41调试的时候就对卡进行重复插拔调试。或者先把里面的程序抹了再插卡进入调试
初始化命令序列,及CMD8->CMD41->CMD2->CMD3这个序列,用C语言发就好用,用汇编发就发生RESPx里面的数据无法用LDR语句读出不详。但是仿佛是CPSM在每次发完指令以后关闭一下就好了。可能要再研究一下CPSM的状态转换图。但是目前这个解决方案有效发送指令以后关闭CPSM

二、本次的任务

将所有的初始化卡的C代码用汇编实现并通过测试。

三、 需要注意的问题

3.1 Card Identification Mode时的时钟频率

在Card Identification Mode中,注意把频率先降下来到400kHz以内。参考《Physical Layer Simplified Specification》第67页

在这里插入图片描述《Physical Layer Simplified Specification》第67页

在进入了Data Transfer Mode以后,可以将时钟调到正常水平。参考《Physical Layer Simplified Specification》第76页

在这里插入图片描述《Physical Layer Simplified Specification》第76页

3.2 CMD0指令的疑似问题

用STM32F407发送CMD0的时候,明明SDIO_STA中已经提示了CMDSENT,但是可以确认的是,卡并没有初始化。但是由于笔者的示波器坏了,所以无法确认到底是指令没有发还是卡没有响应。所以我认为最好还是硬件上给卡的VDD引脚来个可控的设计。另外,上电复位以后,其实只要从CMD8开始往后操作就可以了。

3.3 发送带参数的ACMD41时要注意时间时序和时效

参考《Physical Layer Simplified Specification》第67页,发送ACMD41的时候你要么就一直在轮询发,要么就等一等。这里我采用的是轮询发。因为笔者在底层没有很好的延时理由。
在这里插入图片描述《Physical Layer Simplified Specification》第67页

这里简单说一下。在用汇编写驱动的时候不像在C的时候。只要有点风吹草动就可以怀疑是需要延时一下,加个HAL_Delay(ms)或者其他的什么函数延时一下就往往让程序跑通了。但是在汇编这里,所有的延时一般都是轮询某个标志位来的,都必须要有道理。比如这里,如果不发ACOM41,SD卡是不会在成功初始化后第一时间通知MCU的。所以就选择连续发送ACOM41的方法确认初始化完成状态。

3.4 CPSM的指令发送问题

很多资料都说,把CPSM一直开着,就发指令就好。但是所有的手册都没有体现这一点。笔者也发现,很多时候都是在C语言下好使,但是同样的逻辑用汇编做出来就会出现各种迷惑问题导致程序不能执行。这个跟前面说的时钟频率还真是没有什么关系。经过测试,笔者发现,每次发完指令都把这个CPSM关一下,这个问题就没了。所以笔者推断,这个CPSM状态机并不是希望你一直开着的。随用随开,用完就关。

3.5 调试过程中的SD卡的状态

在DEBUG的时候往往会把程序改好以后直接接入DEBUG,而忽略了卡目前可能处于的状态。根据《Physical Layer Simplified Specification》第50(76)页。已经被分配了RCA的卡不会响应识别指令,包括ACMD41,CMD2。所以DEBUG的时候,比如是先插卡后上电再调试的,还是调试了一次以后改了程序又调试的,其实卡可能一直处在被分配了RCA的状态,那么是不会响应识别指令的。
在这里插入图片描述《Physical Layer Simplified Specification》第50(76)页

四、代码设计

这里就不将peripherals.s里面的代码贴出了。其次,考虑到笔者操作的其实是memory card,不能算是combo card,所以将程序中的原来是combo card的名称改成memory card。

首先是修改了接口。取消了uint32_t (*send_cmd)(uint32_t cmdIndex, uint32_t arg, WaitRspKind waitRsp);方法,换成简单的void (*card_identification)(void);方法。

下面是SDIO_Memory_Card.h的源码

#ifndef _SDIO_Memory_CARD_H_
#define _SDIO_Memory_CARD_H_#include "stdint.h"
typedef enum {waitRsp_noRsp     = 0,waitRsp_shortRsp = 1,waitRsp_longRsp  = 3,
}WaitRspKind;typedef struct {void (*init)(void);void (*card_identification)(void);
}SDIO_Memory_Card_Def;extern const SDIO_Memory_Card_Def SDIO_Memory_Card;
#endif

这个接口的实现文件是SDIO_Memory_Card.s。
在这个文件中单独把“发送命令”作为一个私有方法写出。因为如果不这么做,代码量很大,结构也会比较复杂。在这个方法中,每次发送完了命令都吧CPSM关掉。下次发的时候再打开。每个命令都由调用这个函数的的函数构造,send_cmd方法只是把把参数从r1装入SDIO_ARG命令从r0装入SDIO_CMD,

		get peripherals.srRCC   rn r8
rSDIO  rn r9
rGPIOC rn r10
rGPIOD rn r11SDIO_GPIO_SPEED	equ	GPIOx_OSPEEDR_VERYHIGHarea card_data_area, dataalign 4 
rca	 space 4		 area text, codealign 4
init procpush {r4 - r11, lr}ldr  r8, =RCC_BaseAddrldr  r0, [rRCC, #RCC_APB2ENR]orr  r0, #RCC_APB2ENR_SDIOENstr  r0, [rRCC, #RCC_APB2ENR]ldr  r0, [rRCC, #RCC_AHB1ENR]orr  r0, #RCC_AHB1ENR_GPIOCEN :or: RCC_AHB1ENR_GPIODENstr  r0, [rRCC, #RCC_AHB1ENR]; CLK  	:  PC12; CMD  	:  PD2; DAT_0	:  PC8; DAT_1	:  PC9; DAT_2	:  PC10; DAT_3/CD	:  PC11;ldr  rGPIOC, =GPIOC_BaseAddrldr  r0, [rGPIOC, #GPIOx_MODER]bic  r0, #2_11:shl:(11*2)orr  r0, #GPIOx_MODER_OUTPUT:shl:(11*2)str  r0, [rGPIOC, #GPIOx_MODER]ldr  r0, [rGPIOC, #GPIOx_PUPDR]orr  r0, #GPIOx_PUPDR_PU:shl:(11*2)str  r0, [rGPIOC, #GPIOx_PUPDR]mov  r0, #1:shl:11str  r0, [rGPIOC, #GPIOx_BSRR]mov  r0, #1:shl:(11 + 16)str  r0, [rGPIOC, #GPIOx_BSRR]ldr  rGPIOC, =GPIOC_BaseAddrldr  r0, [rGPIOC, #GPIOx_MODER]
GPIOC_MODER_BITs equ (2_11:shl:(12 * 2)) :or: \(2_11:shl:(11 * 2)) :or: \(2_11:shl:(10 * 2)) :or: \(2_11:shl:(9  * 2)) :or: \(2_11:shl:(8  * 2)) 
GPIOC_MODER_VAL	 equ (GPIOx_MODER_AFIO:shl:(12 * 2)) :or: \(GPIOx_MODER_AFIO:shl:(11 * 2)) :or: \(GPIOx_MODER_AFIO:shl:(10 * 2)) :or: \(GPIOx_MODER_AFIO:shl:(9  * 2)) :or: \(GPIOx_MODER_AFIO:shl:(8  * 2)) 					ldr  r1, =GPIOC_MODER_BITsbic  r0, r1ldr  r1, =GPIOC_MODER_VALorr  r0, r1str  r0, [rGPIOC, #GPIOx_MODER]	 ldr  r0, [rGPIOC, #GPIOx_OTYPER]
GPIOC_OTYPER_BITs	 equ	2_11111:shl:12bic  r0, #GPIOC_OTYPER_BITsstr  r0, [rGPIOC, #GPIOx_OTYPER]ldr  r0, [rGPIOC, #GPIOx_OSPEEDR]	 
GPIOC_OSPEEDR_BITs  equ (2_11:shl:(12 * 2)) :or: \(2_11:shl:(11 * 2)) :or: \(2_11:shl:(10 * 2)) :or: \(2_11:shl:(9  * 2)) :or: \(2_11:shl:(8  * 2)) 
GPIOC_OSPEEDR_VAL	equ (SDIO_GPIO_SPEED:shl:(12 * 2)) :or: \(SDIO_GPIO_SPEED:shl:(11 * 2)) :or: \(SDIO_GPIO_SPEED:shl:(10 * 2)) :or: \(SDIO_GPIO_SPEED:shl:(9  * 2)) :or: \(SDIO_GPIO_SPEED:shl:(8  * 2)) 	 ldr  r1, =GPIOC_OSPEEDR_BITsbic  r0, r1ldr  r1, =GPIOC_OSPEEDR_VALorr  r0, r1str  r0, [rGPIOC, #GPIOx_OSPEEDR]ldr  r0, [rGPIOC, #GPIOx_PUPDR]
GPIOC_PUPDR_BITs  equ   (2_11:shl:(12 * 2)) :or: \(2_11:shl:(11 * 2)) :or: \(2_11:shl:(10 * 2)) :or: \(2_11:shl:(9  * 2)) :or: \(2_11:shl:(8  * 2)) 
GPIOC_PUPDR_VAL	equ     (GPIOx_PUPDR_PU:shl:(12 * 2)) :or: \(GPIOx_PUPDR_PU:shl:(11 * 2)) :or: \(GPIOx_PUPDR_PU:shl:(10 * 2)) :or: \(GPIOx_PUPDR_PU:shl:(9  * 2)) :or: \(GPIOx_PUPDR_PU:shl:(8  * 2))	 ldr  r1, =GPIOC_PUPDR_BITsbic  r0, r1ldr  r1, =GPIOC_PUPDR_VALorr  r0, r1str  r0, [rGPIOC, #GPIOx_PUPDR]
GPIOC_AFIO_BITs		equ		(2_1111:shl:16) :or: \(2_1111:shl:12) :or: \(2_1111:shl:8 ) :or: \(2_1111:shl:4 ) :or: \(2_1111:shl:0 ) 
GPIOC_AFIO_VAL		equ		(12:shl:16) :or: \(12:shl:12) :or: \(12:shl:8 ) :or: \(12:shl:4 ) :or: \(12:shl:0 ) 							ldr  r0, [rGPIOC, #GPIOx_AFRH]ldr  r1, =GPIOC_AFIO_BITsbic  r0, r1ldr  r1, =GPIOC_AFIO_VALorr  r0, r1str  r0, [rGPIOC, #GPIOx_AFRH]ldr  rGPIOD, =GPIOD_BaseAddrldr  r0, [rGPIOD, #GPIOx_MODER]bic  r0, #2_11 :shl:(2 * 2)orr  r0, #GPIOx_MODER_AFIO:shl:(2 * 2)str  r0, [rGPIOD, #GPIOx_MODER]ldr  r0, [rGPIOD, #GPIOx_OTYPER]bic  r0, #2_1 :shl: 2orr  r0, #GPIOx_OTYPER_PP:shl:2str  r0, [rGPIOD, #GPIOx_OTYPER]ldr  r0, [rGPIOD, #GPIOx_OSPEEDR]bic  r0, #2_11:shl:(2*2)orr  r0, #SDIO_GPIO_SPEED:shl:(2*2)str  r0, [rGPIOD, #GPIOx_OSPEEDR]ldr  r0, [rGPIOD, #GPIOx_PUPDR]bic  r0, #2_11:shl:(2 * 2)orr  r0, #GPIOx_PUPDR_PU:shl:(2 * 2)str  r0, [rGPIOD, #GPIOx_PUPDR]ldr  r0, [rGPIOD, #GPIOx_AFRL]bic  r0, #2_1111:shl:8orr  r0, #12:shl:8str  r0, [rGPIOD, #GPIOx_AFRL]; 因为HCLK被配置成了144MHz,APB2分频是2分频,所以APB2的时钟是72MHz。; 为了达到400kHz的初始时钟输出,这里的APB2分频器的数值应该是72M/400k = 180; 所以如果这里写180,那么实际的分频是182分频,那么就肯定是满足要求的ldr  rSDIO, =SDIO_BaseAddrmov  r0, #SDIO_POWER_PWRCTRL_POWERONstr  r0, [rSDIO, #SDIO_POWER]mov  r0, #SDIO_CLKCR_CLKEN:or:SDIO_CLKCR_PWRSAV:or:SDIO_CLKCR_WIDBUS_4WIDE:or:180str  r0, [rSDIO, #SDIO_CLKCR]pop  {r4 - r11, lr}bx   lrendpcard_identification procpush {r4 - r11, lr}ldr  rSDIO, =SDIO_BaseAddrmov  r0, #SDIO_CMD_CPSMENstr  r0, [rSDIO, #SDIO_CMD]mov  r0, #0str  r0, [rSDIO, #SDIO_CMD]mov  r0, #8:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov  r1, #1:shl:8bl   send_cmdmov  r0, #55:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov  r1, #0bl   send_cmdmov  r0, #41:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov  r1, #0bl   send_cmdldr  r4, [rSDIO, #SDIO_RESP1]
set_voltagemov  r0, #55:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov  r1, #0bl   send_cmdmov  r0, #41:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov  r1, r4bl   send_cmdldr  r0, [rSDIO, #SDIO_RESP1]tst  r0, #1:shl:31beq  set_voltageAsk_the_Card_to_Publish_CIDmov  r0, #2:or:SDIO_CMD_WAITRESP_Long:or:SDIO_CMD_CPSMENmov  r1, #0bl   send_cmdAsk_the_Card_to_Publish_RCA	mov  r0, #3:or:SDIO_CMD_WAITRESP_Short:or:SDIO_CMD_CPSMENmov  r1, #0bl   send_cmdldr  r0, [rSDIO, #SDIO_RESP1]	 bfc  r0, #0, #16ldr  r4, =rcastr  r0, [r4]; 目前已经进入了DATA_TRANSFER_MODE
; 将频率设置到高频。这里设置到36MHzldr  r0, [rSDIO, #SDIO_CLKCR]bfc  r0, #0, #8str  r0, [rSDIO, #SDIO_CLKCR]
; 测试DATA_TRANSFER_MODE模式下的指令mov  r0, #9:or:SDIO_CMD_WAITRESP_Long:or:SDIO_CMD_CPSMENldr  r1, =rcaldr  r1, [r1]bl   send_cmdmov  r0, #10:or:SDIO_CMD_WAITRESP_Long:or:SDIO_CMD_CPSMENldr  r1, =rcaldr  r1, [r1]bl   send_cmdpop  {r4 - r11, lr}bx   lrendp; 	 Priviate Function Name: Send_cmd
;	 Args:  r0 - cmd, r1 - arg
;	 实现这个函数align 4		 
send_cmd	procpush {r4 - r11, lr}ldr  rSDIO, =SDIO_BaseAddrmov  r2, #0x7fstr  r2, [rSDIO, #SDIO_ICR]str  r1, [rSDIO, #SDIO_ARG]str  r0, [rSDIO, #SDIO_CMD]
wait_for_responseldr  r0, [rSDIO, #SDIO_STA]tst  r0, #SDIO_STA_CMDREND:or:SDIO_STA_DCRCFAIL:or:SDIO_STA_CTIMEOUTbeq  wait_for_response
;	mov  r0, #0
;	str  r0, [rSDIO, #SDIO_CMD]pop  {r4 - r11, lr}	bx   lrendpalign 4
SDIO_Memory_Card	export SDIO_Memory_Carddcd  init, card_identificationend

卡识别过程的流程就是基本按照手册上说的,

  1. 象征性发一下CMD0,不等回复。
  2. 发CMD8。这句目前看来是很重要的
  3. 发CMD55再发ACMD41,要回复的,且要记住返回值
  4. 发CMD55再发ACMD41,参数就是上一次的返回值。

注意看一下send_cmd(...)私有方法。这里面的流程是

  1. 用0x7f和SDIO_ICR清理一下SDIO_STA
  2. 先写SDIO_CMD,再写SDIO_ARG发送指令及其参数
  3. 忙等回复
  4. 关闭CPSM
  5. 返回

五、测试结果

测试用例这样就比较简单了,代码如下所示。

#include "cmsis_os2.h"                          // CMSIS RTOS header file
#include "SDIO_TestCase.h"
#include "SDIO_Memory_Card.h"
/*----------------------------------------------------------------------------*      Thread 1 'Thread_Name': Sample thread*---------------------------------------------------------------------------*/static osThreadId_t tid_SDIO_Testcase;                        // thread idvoid SDIO_Testcase (void *argument);                   // thread functionint Init_SDIO_Testcase (void) {tid_SDIO_Testcase = osThreadNew(SDIO_Testcase, NULL, NULL);if (tid_SDIO_Testcase == NULL) {return(-1);}return(0);
}__NO_RETURN void SDIO_Testcase (void *argument) {static uint32_t resp;(void)argument;// 在这里做一个测试SDIO_Memory_Card.card_identification(); while (1) {osDelay(101);}
}

进DEBUG,插入SD卡,F5启动。在下面这个地方下断。

在这里插入图片描述
可以发现程序顺利执行,SD卡进入了DATA_TRANSFER_MODE, 并且读到了RCA。

六、结论

经过上面的程序源码设计和测试,可以看到程序顺利运行。有以下的体会。

  1. MCU本身都是有缺陷的。就看有没有暴露出来。如果出现了,能补救就补救。当然也要跟原厂反映。说不定下一版他们就改了。比如这个CMD0疑似发不出去;CPSM每发一个指令就得重启。这就只能用别的办法补救。
  2. 先用400kHz初始化,进入DATA_TRANSFER_MODE以后再改成高速。

这样初始化的任务就基本完成了。下一步就是测试DATA_TRANSFER_MODE中的指令和功能了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/733681.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linuxOPS基础_linux系统注意事项

Linux严格区分大小写 Linux 和Windows不同,Linux严格区分大小写的,包括文件名和目录名、命令、命令选项、配置文件设置选项等。 例如,Win7 系统桌面上有文件夹叫做Test,当我们在桌面上再新建一个名为 test 的文件夹时&#xff0c…

R统计学2 - 数据分析入门问题21-40

往期R统计学文章: R统计学1 - 基础操作入门问题1-20 21. 如何对矩阵按行 (列) 作计算? 使用函数 apply() vec 1:20 # 转换为矩阵 mat matrix (vec , ncol4) # [,1] [,2] [,3] [,4] # [1,] 1 6 11 16 # [2,] 2 7 12 17 # [3,] …

嵌入式Linux串口和 poll() 函数的使用

一、poll() 函数的介绍 poll() 函数用于监控多个文件描述符的变化的函数。它可以用来检查一个或多个文件描述符的状态是否改变,比如是否可读、可写或有错误发生。它常用于处理 I/O 多路复用,这在需要同时处理多个网络连接或文件操作时非常有用。 头文件…

CentOS 7.6安装部署Seafile服务器

今天飞飞和你们分享CentOS 7.6上安装基于MySQL/MariaDB的Seafile服务器的方法,包括下载和安装7.0.5版本、配置数据库、启动服务器等步骤。安装成功后,需要通过nginx反向代理才能访问seafile服务。 通过预编译好的安装包来安装并运行基于 MySQL/MariaDB …

高吞吐SFTP连接池设计方案

背景 在现代的数据驱动环境中,安全文件传输协议(SFTP)扮演着至关重要的角色,它提供了一种安全、可靠的文件传输方式。我们目前项目是一个大型数据集成平台,跟上下游有很多文件对接是通过SFTP协议,当需要处…

果蔬作物疾病防治系统|基于Springboot的果蔬作物疾病防治系统设计与实现(源码+数据库+文档)

果蔬作物疾病防治系统目录 目录 基于Springboot的果蔬作物疾病防治系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、果蔬百科列表 2、公告信息管理 3、公告类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推…

【蓝桥·算法双周赛】第七场分级赛——小白入门赛

2.霓虹【算法赛】 - 蓝桥云课 (lanqiao.cn) st数组用来存第i个位置&#xff0c;这个字母有没有编号j #include<bits/stdc.h> const int N1e610; using lllong long; std::map<std::string,std::string> mp;std::string a,aa; int st[N][10];// int stt[N][10];//对…

Qt 拖动事件

文章目录 1 自定义控件 TextEdit2 实现打开文件功能3 实现鼠标滚轮放大字体 QEvent::DragEnter 当拖动文件进入到窗口/控件中时&#xff0c;触发该事件&#xff0c;它对应的子类是QDragEnterEvent QEvent::DragLeave 当拖动文件离开窗口/控件时&#xff0c;触发该事件&#xff…

WordPress高端后台美化WP Adminify Pro优化版

后台UI美化WP Adminify Pro修改自定义插件&#xff0c;适合建站公司和个人使用&#xff0c;非常高大上&#xff0c;下载地址&#xff1a;WP Adminify Pro优化版 修复记录&#xff1a; 1、修复已知BUG 2、修复手机版兼容问题 3、修复打开速度&#xff0c;原版打开速度太慢 4…

自动裁剪人脸:简化你的数字人素材准备

在做数字人时,需要对采集的数据进行预处理,然后才能进行模型训练, 预处理常用的操作有:去背景 音频重采样 视频裁剪 音频特征提取等等,今天我们来分享一个自动化脚本: 对原图/视频进行人脸检测并根据目标尺寸以人脸为中心进行裁剪. 目录 1. 效果 2. 对图片进行裁剪 3.对视频…

DeepLearning in Pytorch|共享单车预测NN详解(思路+代码剖析)

目录 概要 一、代码概览 二、详解 基本逻辑 1.数据准备 2.设计神经网络 初版 改进版 测试 总结 概要 原文链接&#xff1a;DeepLearning in Pytorch|我的第一个NN-共享单车预测 我的第一个深度学习神经网络模型---利用Pytorch设计人工神经网络对某地区租赁单车的使用…

umi4 项目使用 keepalive 缓存页面(umi-plugin-keep-alive、react-activation)

umi4使用keepalive 配置文件config\config.ts export default defineConfig({plugins: [umi-plugin-keep-alive], });安装add umi-plugin-keep-alive yarn add umi-plugin-keep-alive页面 A import { KeepAlive, history, useAliveController } from umijs/max; const Page…

CSAPP Malloc lab

CSAPP Malloc Lab 目标 实现一个简单的动态存储分配器。 评分标准 空间利用率应当减少internal 和 external fragmentation. memory utilization memory utilization payload / heap size fragmentation internal fragmentation external fragmentation throughput T 越接…

【深度学习笔记】6_9 深度循环神经网络deep-rnn

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 6.9 深度循环神经网络 本章到目前为止介绍的循环神经网络只有一个单向的隐藏层&#xff0c;在深度学习应用里&#xff0c;我们通常会用…

嵌入式Qt 制作一个登录对话框

一.登录对话框需求分析 二.代码实现 main.c&#xff1a; #include <QtGui/QApplication> #include "widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); }Widget.h&#xff1a; #ifndef _WIDGET_H_…

为什么选择 Flink 做实时处理

优质博文&#xff1a;IT-BLOG-CN 为什么选择 Flink 【1】流数据更真实地反映了我们的生活方式&#xff08;实时聊天&#xff09;&#xff1b; 【2】传统的数据架构是基于有限数据集的&#xff08;Spark 是基于微批次数据处理&#xff09;&#xff1b; 【3】我们的目标&#xf…

ELK-介绍及Elasticsearch集群搭建

ELK是三个开源软件的缩写&#xff0c;分别为Elasticsearch、Logstash、kibana它们都是开源软件。后来新增了一个FileBeat&#xff0c;它是一个轻量及的日志收集处理工具&#xff0c;因为Logstash由java程序开发&#xff0c;比较消耗内存资源&#xff0c;后来将Logstash使用go语…

【论文阅读】(2024.03.05-2024.03.15)论文阅读简单记录和汇总

(2024.03.05-2024.03.15)论文阅读简单记录和汇总 2024/03/05&#xff1a;随便简单写写&#xff0c;以后不会把太详细的记录在CSDN&#xff0c;有道的Markdown又感觉不好用。 目录 &#xff08;ICMM 2024&#xff09;Quality Scalable Video Coding Based on Neural Represent…

.net6Api后台+uniapp导出Excel

之前的这个是vue3写法&#xff0c;后端是.net6Api.net6Api后台VUE3前端实现上传和下载文件全过程_vue3 下载文件-CSDN博客 在现在看来似乎搞的复杂了&#xff0c;本次记录一下.net6Api后台uniapp导出Excel。 后端和之前的不一样&#xff0c;前端也和之前的不一样&#xff0c;…

【C语言】深入理解指针(进阶篇)

一、数组名的理解 数组名就是地址&#xff0c;而且是数组首元素的地址。 任务&#xff1a;运行以下代码&#xff0c;看数组名是否是地址。 #include <stdio.h> int main() {int arr[] { 1,2,3,4,5,6,7,8,9,0 };printf("&arr[0] %p\n", &arr[0]);pri…