platfrom tree架构下实现3-Wire驱动(DS1302)

目录

概述

1 认识DS1302

1.1 DS1302 硬件电路

1.2 操作DS1302 

1.3 注意要点

2 IO引脚位置

3 添加驱动节点

3.1 更新内核.dts

3.2 更新板卡.dtb

4 驱动程序实现

4.1  编写驱动程序

4.2 编写驱动程序的Makefile

4.3 安装驱动程序

5 验证驱动程序

5.1 编写测试程序

5.2 编写测试程序代码Makefile

5.3 运行测试App

6 实时波形分析


概述

       本文介绍在platform-tree框架下如何实现复杂总线驱动程序,以DS1302为例,详细介绍如何在linux内核中,添加driver tree节点,以及如何在驱动程序中,调用多线接口IO。

1 认识DS1302

DS1302 数据手册和产品信息 | 亚德诺(ADI)半导体 (analog.com)

         DS1302是一款使用非常普遍的实时时钟芯片,可提供,年月日,时分秒,week实时数据。其和MCU直接的电路也非常简单,只需3个引脚(CE, IO , CLK)。

主要特性

  • 完全管理所有计时功能
    • 实时时钟可为秒、分、小时、日期、月、星期和年计数,闰年补偿有效期至2100年
    • 31 x 8电池供电通用RAM
  • 通过简单的串行端口与大多数微控制器进行接口
    • 简单的3线接口
    • TTL兼容(VCC = 5V)
    • 用于读取或写入时钟或RAM数据的单字节或多字节(突发模式)数据传输
  • 低功耗运行可延长备用电池运行时间
    • 2.0V至5.5V全面运行
    • 2.0V时电流消耗小于300nA
  • 8引脚DIP和8引脚SO封装充分减少了所需空间
  • 可选工业温度范围:-40°C至+85°C支持在多种应用中工作

1.1 DS1302 硬件电路

CE: 使能引脚

IO: 数据引脚(读/写数据)

SCLK: 时钟引脚

1.2 操作DS1302 

读寄存器波形如下:

CE: 高电平有效

写地址时,CLK上升沿有效

读数据时,CLK下降沿有效

写寄存器波形:

CE: 高电平有效

写地址时,CLK上升沿有效

写数据时,CLK上升沿有效

1.3 注意要点

从DS1302中读取的时间数据位BCD码,所以,在实际运用时,需要将其转化为十进制,例如:

// 从寄存器中读出的值为: 0x14,使用时需要将其转化为14,方法如下:
static unsigned char bcd_2_dem(unsigned char x)
{return (x>>4)*10+(x&0x0f);                   //高4位乘以10,再加上低4位,即得到数值
}

初始化DS1302寄存器时,要进行上述数据转换的逆操作,方法如下:

// 如果要配置分钟数为25分钟,写到寄存器的值应该是: 0x25。转换方法如下:unsigned char dem_2_bcd( unsigned char val )
{return (((val/10)& 0x0f)<<4)|((val%10)&0x0f);
}

2 IO引脚位置

DS1302芯片在测试底板上的IO引脚位置:

//GPIO4_24:  DS1302_CE
//GPIO4_26:  DS1302_IO
//GPIO4_28:  DS1302_CLKCE_1302  = P2^4;   -----   D3   -- GPIO4_24
IO_1302  = P2^3;   -----   D5   -- GPIO4_26
CLK_1302 = P2^2;   -----   D7   -- GPIO4_28

硬件实物图:

在板卡ATK-DL6Y2C上DS1302的对应接口:

3 添加驱动节点

3.1 更新内核.dts

DS1302引脚和IMX.6ULL引脚对应关系:

GPIO4_24:  DS1302_CE   
GPIO4_26:  DS1302_IO
GPIO4_28:  DS1302_CLK

.dts文件路径:

/home/mftang/linux_workspace/study_atk_dl6y2c/kernel/atk-dl6u2c/arch/arm/boot/dts/imx6ull-14x14-evk.dts

1) 使用 i.MX Pins Tool v6 配置IO Pin

2) 添加IOMUXC数据至.dts文件

3)添加设备compatible至.dts文件

代码信息

	//mftang: user's ds1302, 2024-1-31//GPIO4_24:  DS1302_CE//GPIO4_26:  DS1302_IO//GPIO4_28:  DS1302_CLKmftangds1302 {compatible = "atk-dl6y2c,ds1302";pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpio_mftangds1302>;ce-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>;io-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>;clk-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;status = "okay";};	

4) 编译.dts文件

在内核根目录下使用

make dtbs

5) 复制 .dtb 文件至NFS共享目录

cp arch/arm/boot/dts/imx6ull-14x14-emmc-4.3-480x272-c.dtb  /home/mftang/nfs/atk_dl6y2c/

3.2 更新板卡.dtb

开发版中的.dtb文件存放位置:

cd /run/media/mmcblk1p1

在开发板上把 .dtb文件复制到应用目录中:

cp /mnt/atk_dl6y2c/imx6ull-14x14-emmc-4.3-480x272-c.dtb /run/media/mmcblk1p1

复制.dtb文件到相应的运行目录,然后重新板卡。在/proc/device-tree中可以看见device节点,然后可以在driver中使用该节点。

4 驱动程序实现

4.1  编写驱动程序

驱动程序源码:

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     : drv_09_tree_hs0038.c
作者       : tangmingfei2013@126.com
版本       : V1.0
描述       : ds1302 驱动程序
其他       : 无
日志       : 初版V1.0 2024/02/01  使用方法:
1) 在.dts文件中定义节点信息//mftang: user's ds1302, 2024-1-31//GPIO4_24:  DS1302_CE//GPIO4_26:  DS1302_IO//GPIO4_28:  DS1302_CLKmftangds1302 {compatible = "atk-dl6y2c,ds1302";pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpio_mftangds1302>;gpios-ce = <&gpio4 24 GPIO_ACTIVE_HIGH>;gpios-io = <&gpio4 26 GPIO_ACTIVE_HIGH>;gpios-clk = <&gpio4 28 GPIO_ACTIVE_HIGH>;status = "okay";};2) 在驱动匹配列表 
static const struct of_device_id ds1302_of_match[] = {{ .compatible = "atk-dl6y2c,ds1302" },{ } // Sentinel
};3) 驱动使用方法:
typedef struct{unsigned char second;unsigned char minute;unsigned char hour;unsigned char week;unsigned char day;unsigned char month;unsigned char year;
}stru_ds1302_rtc;stru_ds1302_rtc rtc;read(fd, &rtc, sizeof(stru_ds1302_rtc));***************************************************************/
#include <linux/module.h>
#include <linux/poll.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <asm/current.h>#define DEVICE_NAME      "treeds1302"     // dev/treeds1302/* ds1302dev设备结构体 */
struct ds1302stru_dev{dev_t   devid;                 /* 设备号          */struct  cdev cdev;             /* cdev            */struct  class *class;          /* 类              */struct  device *device;        /* 设备            */int     major;                 /* 主设备号        */struct  device_node *node;     /* ds1302设备节点  */int     userds1302;            /* ds1302 GPIO标号 */struct  gpio_desc *pin_ce;struct  gpio_desc *pin_io;struct  gpio_desc *pin_clk;
};struct ds1302stru_dev ds1302dev;         /* ds1302设备 */
static wait_queue_head_t ds1302_wq;static const unsigned char RTC_REG[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};/*device 相关的驱动程序 
*/
static unsigned char bcd_2_dem(unsigned char x)
{return (x>>4)*10+(x&0x0f);                   //高4位乘以10,再加上低4位,即得到数值
}static void ds1302_wr_byte(unsigned char dat)    //DS1302:写入操作
{unsigned char i;for(i=0;i<8;i++){if(dat&0x01){                            //从低字节开始传送gpiod_direction_output(ds1302dev.pin_io, 1); // ds1302 io = 1}else {gpiod_direction_output(ds1302dev.pin_io, 0); // ds1302 io = 0}// CLK_1302=0;  gpiod_direction_output(ds1302dev.pin_clk, 0);// CLK_1302=1;gpiod_direction_output(ds1302dev.pin_clk, 1);dat = dat>>1;}
}static unsigned char ds1302_rd_byte(void)  //DS1302:读取操作   
{unsigned char i,temp = 0;// IO_1302 as inputgpiod_direction_input( ds1302dev.pin_io );for(i=0;i<8;i++){if( gpiod_get_value(ds1302dev.pin_io) )temp=temp|0x80;elsetemp=temp&0x7f;// CLK_1302 = 1gpiod_direction_output(ds1302dev.pin_clk, 1);// CLK_1302 = 0gpiod_direction_output(ds1302dev.pin_clk, 0);temp=temp>>1;}return(temp);
}static void write_ds1302_reg(unsigned char addr,unsigned char dat)
{unsigned long flags;local_irq_save(flags);//CLK_1302=0;gpiod_direction_output(ds1302dev.pin_clk,0);//CE_1302=1; gpiod_direction_output(ds1302dev.pin_ce, 1);ds1302_wr_byte(addr); ds1302_wr_byte(dat);//CE_1302=0;gpiod_direction_output(ds1302dev.pin_ce, 0);//CLK_1302=0;gpiod_direction_output(ds1302dev.pin_clk,0);local_irq_restore(flags); 
}static unsigned char read_ds1302_reg(unsigned char addr)   
{unsigned long flags;unsigned char temp;local_irq_save(flags);// CLK_1302=0gpiod_direction_output(ds1302dev.pin_clk, 0);// CE_1302=1 gpiod_direction_output(ds1302dev.pin_ce, 1);ds1302_wr_byte(addr);      //写入地址temp = ds1302_rd_byte();// CE_1302=0gpiod_direction_output(ds1302dev.pin_ce, 0);// CLK_1302=0gpiod_direction_output(ds1302dev.pin_clk, 0);local_irq_restore(flags);return(temp);
} static void ds1302_wr_wp(unsigned char wp)
{if (wp)write_ds1302_reg(0x8e,0x80);elsewrite_ds1302_reg(0x8e,0x00);
}static void ds1302_stop(unsigned char flag)
{unsigned char chold;chold = read_ds1302_reg(0x81);if (flag)write_ds1302_reg(0x80,chold|0x80);elsewrite_ds1302_reg(0x80,chold&0x7f);
}static unsigned char ds1302_read_rtc( unsigned char reg )
{unsigned char dat;dat = read_ds1302_reg(reg);return  bcd_2_dem(dat);
}static void ds1302_get_rtc( unsigned char *buff)
{int LEN = sizeof(RTC_REG);int i = 0;for( i = 0; i < LEN; i++ ){buff[i] = ds1302_read_rtc( RTC_REG[i]|0x01);}
}static void ds1302_drv_init( unsigned char *buff )
{unsigned long flags;unsigned char temp,val;int LEN = sizeof(RTC_REG);int i;ds1302_stop(1);    // stop clockds1302_wr_wp(0);   // enable write local_irq_save(flags);for ( i=0; i < LEN; i++){val = buff[i];temp = (((val/10)& 0x0f)<<4)|((val%10)&0x0f);write_ds1302_reg( RTC_REG[i], temp );}local_irq_restore(flags);ds1302_wr_wp(1);  // disable write ds1302_stop(0);   // enable clock 
}/*linux driver 驱动接口: 实现对应的open/read/write等函数,填入file_operations结构体
*/
static ssize_t ds1302_drv_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int LEN = sizeof(RTC_REG);unsigned char tempbuff[LEN];int length;length = copy_from_user(tempbuff, buf, LEN);if( cnt != LEN ){printk(" %s line %d write ds1302 register error! \r\n",  __FUNCTION__, __LINE__);return 0;}else{ds1302_drv_init( tempbuff );}return cnt;
}static ssize_t ds1302_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{int LEN = sizeof(RTC_REG);unsigned char tempbuff[LEN];int length;ds1302_get_rtc( tempbuff );length = copy_to_user(buf, tempbuff, LEN);return length;
}static unsigned int ds1302_drv_poll(struct file *fp, poll_table * wait)
{printk(" %s line %d \r\n",  __FUNCTION__, __LINE__);return 0;
}static int ds1302_drv_close(struct inode *node, struct file *file)
{printk(" %s line %d \r\n",  __FUNCTION__, __LINE__);return 0;
}/* 定义driver的file_operations结构体
*/
static struct file_operations ds1302_fops = {.owner   = THIS_MODULE,.write   = ds1302_drv_write,.read    = ds1302_drv_read,.poll    = ds1302_drv_poll,.release = ds1302_drv_close,
};/* 1. 从platform_device获得GPIOmftangds1302 {compatible = "atk-dl6y2c,ds1302";pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpio_mftangds1302>;ce-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>;io-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>;clk-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;status = "okay";};*/
static int ds1302_probe(struct platform_device *pdev)
{printk("ds0302 driver and device was matched!\r\n");/* 1. 获得硬件信息 */ds1302dev.pin_ce = gpiod_get(&pdev->dev, "ce", 0);if (IS_ERR(ds1302dev.pin_ce)){printk("%s line %d get ce parameter error! \n", __FUNCTION__, __LINE__);}ds1302dev.pin_io = gpiod_get(&pdev->dev, "io", 0);if (IS_ERR(ds1302dev.pin_io)){printk("%s line %d get io parameter error! \n", __FUNCTION__, __LINE__);}ds1302dev.pin_clk = gpiod_get(&pdev->dev, "clk", 0);if (IS_ERR(ds1302dev.pin_clk)){printk("%s line %d get clk parameter error! \n", __FUNCTION__, __LINE__);}/* 2. device_create */device_create( ds1302dev.class, NULL, MKDEV( ds1302dev.major, 0 ), NULL, DEVICE_NAME);  return 0;
}static int ds1302_remove(struct platform_device *pdev)
{device_destroy( ds1302dev.class, MKDEV( ds1302dev.major, 0));gpiod_put(ds1302dev.pin_ce);gpiod_put(ds1302dev.pin_io);gpiod_put(ds1302dev.pin_clk);return 0;
}static const struct of_device_id atk_dl6y2c_ds1302[] = {{ .compatible = "atk-dl6y2c,ds1302" },{ },
};/* 1. 定义platform_driver */
static struct platform_driver ds1302_pltdrv = {.probe      = ds1302_probe,.remove     = ds1302_remove,.driver     = {.name   = "atk_ds1302",.of_match_table = atk_dl6y2c_ds1302,},
};/* 2. 在入口函数注册platform_driver */
static int __init ds1302_init(void)
{printk("%s line %d\n",__FUNCTION__, __LINE__);/* register file_operations  */ds1302dev.major = register_chrdev( 0, DEVICE_NAME,     /* device name */&ds1302_fops);  /* create the device class  */ds1302dev.class = class_create(THIS_MODULE, "ds1302_class");if (IS_ERR(ds1302dev.class)) {printk("%s line %d\n", __FUNCTION__, __LINE__);unregister_chrdev( ds1302dev.major, DEVICE_NAME);return PTR_ERR( ds1302dev.class );}init_waitqueue_head(&ds1302_wq);return platform_driver_register(&ds1302_pltdrv); 
}/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数*    卸载platform_driver*/
static void __exit ds1302_exit(void)
{printk("%s line %d\n", __FUNCTION__, __LINE__);platform_driver_unregister(&ds1302_pltdrv);class_destroy(ds1302dev.class);unregister_chrdev(ds1302dev.major, DEVICE_NAME);
}/* 7. 其他完善:提供设备信息,自动创建设备节*/module_init(ds1302_init);
module_exit(ds1302_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("tangmingfei2013@126.com");

4.2 编写驱动程序的Makefile

PWD := $(shell pwd)KERNEL_DIR=/home/mftang/linux_workspace/study_atk_dl6y2c/kernel/atk-dl6u2c
ARCH=arm
CROSS_COMPILE=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-export  ARCH  CROSS_COMPILEobj-m:= drv_10_tree_ds1302.oall:$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modulesclean:rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.order *.symvers

4.3 安装驱动程序

在dev/目录下查看驱动程序

5 验证驱动程序

5.1 编写测试程序

测试程序源码

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名  : test_10_tree_ds1302.c
作者    : tangmingfei2013@126.com
版本    : V1.0
描述    : ds1302 测试程序,用于测试 drv_10_tree_ds1302
日志    : 初版V1.0 2024/1/29***************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>#define DEV_NAME    "/dev/treeds1302"typedef struct{unsigned char second;unsigned char minute;unsigned char hour;unsigned char week;unsigned char day;unsigned char month;unsigned char year;
}stru_ds1302_rtc;stru_ds1302_rtc rtc;int main(int argc, char **argv)
{int fd;fd = open(DEV_NAME, O_RDWR);if (fd < 0){printf("can not open file %s \r\n", DEV_NAME);return -1;}// init rtc rtc.year = 24;rtc.month = 2;rtc.day = 1;rtc.week = 4;rtc.hour = 18;rtc.minute = 2;rtc.second = 0;write(fd, &rtc, sizeof(stru_ds1302_rtc));while(1){read(fd, &rtc, sizeof(stru_ds1302_rtc));printf(" %02d-%02d-%02d week %d   %02d:%02d:%02d \r\n",  rtc.year, rtc.month, rtc.day, rtc.week,rtc.hour,rtc.minute, rtc.second);sleep(1);}close(fd);return 0;
}

5.2 编写测试程序代码Makefile

CFLAGS= -Wall -O2
CC=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
STRIP=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-striptest_10_tree_ds1302: test_10_tree_ds1302.o$(CC) $(CFLAGS) -o test_10_tree_ds1302 test_10_tree_ds1302.o$(STRIP) -s test_10_tree_ds1302clean:rm -f test_10_tree_ds1302 test_10_tree_ds1302.o

5.3 运行测试App

运行测试程序后,系统会初始化DS1302的时间,然后每隔1s从芯片中读取时间

6 实时波形分析

分析一个简单的波形,从寄存器:0x81中读取秒数据,秒数为57,具体波形图如下

读一个完整的年月日时分秒波形

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

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

相关文章

何时以及如何选择制动电阻

制动电阻的选择是优化变频器应用的关键因素 制动电阻器在变频器中是如何工作的&#xff1f; 制动电阻器在 VFD 应用中的工作原理是将电机减速到驱动器设定的精确速度。它们对于电机的快速减速特别有用。制动电阻还可以将任何多余的能量馈入 VFD&#xff0c;以提升直流母线上的…

Electron实战(二):将Node.js和UI能力(app/BrowserWindow/dialog)等注入html

文章目录 设置webPreferences参数安装electron/remotemain进程中初始化html中使用dialog踩坑参考文档 上一篇&#xff1a;Electron实战(一)&#xff1a;环境搭建/Hello World/打包exe 设置webPreferences参数 为了能够在html/js中访问Node.js提供fs等模块&#xff0c;需要在n…

QT 范例阅读:系统托盘 The System Tray Icon example

main.cpp QApplication app(argc, argv);//判断系统是否支持 系统托盘功能if (!QSystemTrayIcon::isSystemTrayAvailable()) {QMessageBox::critical(0, QObject::tr("Systray"),QObject::tr("I couldnt detect any system tray ""on this system.&qu…

利用jmeter完成简单的压力测试

Jmeter是一个非常好用的压力测试工具。Jmeter用来做轻量级的压力测试&#xff0c;非常合适&#xff0c;只需要十几分钟&#xff0c;就能把压力测试需要的脚本写好。 1、什么是压力测试 顾名思义&#xff1a;压力测试&#xff0c;就是 被测试的系统&#xff0c;在一定的访问压…

下载、安装Jenkins

进入官网 下载Jenkins https://www.jenkins.io 直接点击Download 一般是下长期支持版 因为它是java写的&#xff0c;你要运行它&#xff08;Jenkins.war&#xff09;肯定要有java环境 有两种方式去运行它&#xff0c;一种是下载Tomcat&#xff08;是很经典的java容器或者jav…

爬虫工作量由小到大的思维转变---<第四十五章 Scrapyd 关于gerapy遇到问题>

前言: 本章主要是解决一些gerapy遇到的问题,会持续更新这篇! 正文: 问题1: 1400 - build.py - gerapy.server.core.build - 78 - build - error occurred (1, [E:\\项目文件名\\venv\\Scripts\\python.exe, setup.py, clean, -a, bdist_uberegg, -d, C:\\Users\\Administrat…

红队渗透靶机:TIKI: 1

目录 信息收集 1、arp 2、nmap 3、nikto 4、whatweb 目录探测 1、dirsearch 2、gobuster WEB web信息收集 searchsploit cms信息收集 ssh登录 提权 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:2…

数据结构-数组

1.容器 容器用于容纳元素集合&#xff0c;并对元素集合进行管理和维护&#xff0e; 传统意义上的管理和维护就是&#xff1a;增&#xff0c;删&#xff0c;改&#xff0c;查&#xff0e; 我们分析每种类型容器时&#xff0c;主要分析其增&#xff0c;删&#xff0c;改&#xf…

iMazing 3中文版双平台版本同步,iOS 设备在 Windows 上也能自动备份了

自从WWDC 2019 宣布 iTunes 退役后&#xff0c;也许很多小伙伴都对「上位者」iMazing 有所耳闻。 这款设计更加人性化、功能细致强大的 iOS 备份管理工具。 iMazing 支持在 Windows 及 Mac 上运行&#xff0c;而这个月 Windows 版本更新至 2.17. 之后&#xff0c;iMazing 的双…

Kubernetes基础(十一)-CNI网络插件用法和对比

1 CNI概述 1.1 什么是CNI&#xff1f; Kubernetes 本身并没有实现自己的容器网络&#xff0c;而是借助 CNI 标准&#xff0c;通过插件化的方式来集成各种网络插件&#xff0c;实现集群内部网络相互通信。 CNI&#xff08;Container Network Interface&#xff0c;容器网络的…

如何构建起自己的伦敦银交易系统?

投资者在市场这个江湖中行走&#xff0c;就需要有一技防身&#xff0c;不然很容易会被市场的风险所淹没&#xff0c;这个“一技”指的就是伦敦银交易系统。如果投资者要构建起自己的伦敦银交易系统&#xff0c;应该从哪几个方面着手呢&#xff1f;下面我们就来讨论一下。 分析方…

Jenkins(本地Windows上搭建)上传 Pipeline构建前端项目并将生成dist文件夹上传至指定服务器

下载安装jdk https://www.oracle.com/cn/java/technologies/downloads/#jdk21-windows 下载jenkins window版 双击安装 https://www.jenkins.io/download/thank-you-downloading-windows-installer-stable/ 网页输入 http://localhost:8088/ 输入密码、设置账号、安装推…

2024-2-4-复习作业

源代码&#xff1a; #include <stdio.h> #include <stdlib.h> typedef int datatype; typedef struct Node {datatype data;struct Node *next;struct Node *prev; }*DoubleLinkList;DoubleLinkList create() {DoubleLinkList s(DoubleLinkList)malloc(sizeof(st…

【Web】CVE-2021-22448 Log4j RCE漏洞学习

目录 复现流程 漏洞原理 复现流程 启动HTTP->启动LDAP->执行Log4j vps起个http服务,放好Exploit.class这个恶意字节码 LDAPRefServer作为恶意LDAP服务器 import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import javax.ne…

WordPress主题YIA如何将首页的置顶小工具改为站长推荐小工具?

YIA主题有“置顶推荐”小工具&#xff0c;首页文章列表页有置顶功能&#xff0c;可在YIA主题设置 >> 列表 >> 首页-最新发布 >> 显示置顶文章中开启或关闭。如果将“置顶推荐”小工具添加到“首页顶栏”&#xff0c;同时也开启首页最新发布的“显示置顶文章”…

代码生成器(新):mybatis-plus-generator使用指南

代码生成器&#xff08;新&#xff09;官网 后端代码&#xff1a;点击查看 LearnElementUiAndSpringBoot 提醒&#xff1a;LearnElementUiAndSpringBoot下载完后&#xff0c;在运行调试 Main.java里的main方法之前&#xff0c;除了utils包和Main.java文件&#xff0c;其他包需…

小程序中封装下拉选择框

小程序中没有现成的下拉选择组件&#xff0c;有个picker组件&#xff0c;但是是底部弹出的&#xff0c;不满足我的需求&#xff0c;所以重新封装了一个。 封装的下拉组件 html部分&#xff1a; <view class"select_all_view"><!-- 内容说明&#xff0c;可…

C# OMRON PLC FINS TCP协议简单测试

FINS(factory interface network service)通信协议是欧姆龙公司开发的用于工业自动化控制网络的指令&#xff0f;响应系统。运用 FINS指令可实现各种网络间的无缝通信&#xff0c;包括用于信息网络的 Etherne(以太网)&#xff0c;用于控制网络的Controller Link和SYSMAC LINK。…

es6中标签模板

之所以写这篇文章&#xff0c;是因为标签模板是一个很容易让人忽略的知识点 首先我们已经非常熟悉模板字符串的使用方法 const name "诸葛亮" const templateString hello, My name is ${name}标签模板介绍 这里的标签模板其实不是模板&#xff0c;而是函数调用…

【Redis】实现缓存及相关问题

Redis实现缓存及相关问题 认识缓存 缓存就是数据交换的缓冲区&#xff0c;是存贮数据的临时地方&#xff0c;一般读写性能较高。 缓存的作用&#xff1a; 降低后端负载提高读写效率&#xff0c;降低响应时间 缓存的成本&#xff1a; 数据一致性成本代码维护成本运维成本 …