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

news2024/11/28 15:44:09

目录

概述

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_CLK

CE_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_CLK
	mftangds1302 {
			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_CLK
    mftangds1302 {
            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 input
   gpiod_direction_input( ds1302dev.pin_io );
   
   for(i=0;i<8;i++)
   {
        if( gpiod_get_value(ds1302dev.pin_io) )
            temp=temp|0x80;
        else
            temp=temp&0x7f;

        // CLK_1302 = 1
        gpiod_direction_output(ds1302dev.pin_clk, 1);
        // CLK_1302 = 0
        gpiod_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=0
   gpiod_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=0
   gpiod_direction_output(ds1302dev.pin_ce, 0);
   // CLK_1302=0
   gpiod_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);
  else
    write_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);
  else
    write_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 clock
    ds1302_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获得GPIO
    mftangds1302 {
            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_COMPILE

obj-m:= drv_10_tree_ds1302.o

all:
	$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules


clean:
	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-strip


test_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_ds1302

clean:
	rm -f test_10_tree_ds1302 test_10_tree_ds1302.o

5.3 运行测试App

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

6 实时波形分析

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

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

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

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

相关文章

机器学习数据预处理--连续变量分箱

文章目录 原理概念等宽分箱等频分箱聚类分箱有监督分箱 原理概念 连续变量分箱即对连续型字段进行离散化处理&#xff0c;也就是将连续型字段转化为离散型字段。连续字段的离散过程如下所示&#xff1a; 连续变量的离散过程也可以理解为连续变量取值的重新编码过程&#xff0c…

Qt环境搭建+简单程序实现

Qt是什么 Qt是一个跨平台的C图形用户界面应用程序框架。 框架的本质就是一群大佬发明的让菜鸡写出来的代码也也比较规范 也就是限制程序员的自由&#xff0c;让程序员写出来的代码规范。 库和框架有相似性。 库是被程序员调用的&#xff0c;&#xff08;程序员是主体&…

PyTorch 2.2 中文官方教程(二)

在 YouTube 上介绍 PyTorch PyTorch 介绍 - YouTube 系列 原文&#xff1a;pytorch.org/tutorials/beginner/introyt.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 介绍 || 张量 || 自动微分 || 构建模型 || TensorBoard 支持 || 训练模型 || 模型理解 作者&a…

05 - python操作JSON

JSON认识 JSON&#xff0c;一种轻量级的文本数据交换格式&#xff0c;比XML更小更快&#xff0c;更易解析&#xff0c;爬虫经常要获取接口数据&#xff0c;接口数据就是JSON格式的。 格式示例 # 格式1&#xff1a;JSON 对象 {"name": "李嘉图", "a…

pytorch索引和切片

目录 1. 按索引方式取数据2. 以python切片方式取数据3. 指定index取数据4. ...代表除其前后指定维度外的所有维度5. masked_select() 使用掩码选择元素6. take 矩阵打平后选取 1. 按索引方式取数据 a[0,0,2,4] 其中0&#xff0c;0&#xff0c;2&#xff0c;4是索引从0开始 2. …

3.0 Hadoop 概念

本章着重介绍 Hadoop 中的概念和组成部分&#xff0c;属于理论章节。如果你比较着急可以跳过。但作者不建议跳过&#xff0c;因为它与后面的章节息息相关。 Hadoop 整体设计 Hadoop 框架是用于计算机集群大数据处理的框架&#xff0c;所以它必须是一个可以部署在多台计算机上…

灵活应对:策略模式在软件设计中的应用

策略模式是一种行为型设计模式&#xff0c;它允许定义一系列算法&#xff0c;并将每个算法封装起来&#xff0c;使它们可以互换使用。策略模式让算法的变化独立于使用算法的客户端&#xff0c;使得在不修改原有代码的情况下切换或扩展新的算法成为可能。 使用策略模式的场景包…

无人机遥感技术在地质灾害监测应用分析,多旋翼无人机应急救援技术探讨

地质灾害是指在地球的发展演变过程中&#xff0c; 由各种自然地质作用和人类活动所形成的灾害性地质事件。给人民的生命和财产安全带来严重威胁&#xff0c;因此有必要开展地质灾害预测预报、灾害应急和风险区划 遥感技术的快速发展为我们提供了一种获取实时灾害信息的可靠手段…

使用WPS制作三线表

点击边框和底纹点击1、2、3、4并且应用于表格点击确定 再次选中表格点击右键表格属性选择边框和底纹 选中表格第一行右键点击表格属性选择边框和底纹 如果表格中存在虚线

离线数仓-数据治理

目录 一、前言 1.1 数据治理概念 1.2 数据治理目标 1.3 数据治理要解决的问题 1.3.1 合规性 元数据合规性 数据质量合规性 数据安全合规性 1.3.2 成本 存储资源成本 计算资源成本 二、数据仓库发展阶段 2.1 初始期 2.2 扩张期 2.3 缓慢发展期 2.4 变革期 三、…

基于hadoop+spark的大规模日志的一种处理方案

概述: CDN服务平台上有为客户提供访问日志下载的功能,主要是为了满足在给CDN客户提供服务的过程中,要对所有的记录访问日志,按照客户定制的格式化需求以小时为粒度(或者其他任意时间粒度)进行排序、压缩、打包,供客户进行下载,以便进行后续的核对和分析的诉求。而且CDN…

判断和循环 - switch语句和练习

switch语句格式 switch(表达式) {case 值1:语句体1;break;case 值2:语句体2;break;...default:语句体n1;break; }执行流程&#xff1a; 首先计算表达式的值。依次和case后面的值进行比较&#xff0c;如果有对应的值&#xff0c;就会执行相应的语句&#xff0c;在执行的过程中…

vue项目线上页面刷新报404 解决方法

一.修改配置文件 nginx.conf &#xff0c;并重新加载或重启 我的nginx版本是1.9.9 location / {try_files $uri $uri/ /index.html; }原因&#xff1a; 打包后的dist下只有一个 index.html 文件及一些静态资源&#xff0c;这个是因为Vue是单页应用(SPA)&#xff0c;只有一个…

《Python 网络爬虫简易速速上手小册》第6章:Python 爬虫的优化策略(2024 最新版)

文章目录 6.1 提高爬虫的效率6.1.1 重点基础知识讲解6.1.2 重点案例&#xff1a;使用 asyncio 和 aiohttp 实现异步爬虫6.1.3 拓展案例 1&#xff1a;利用 Scrapy 的并发特性6.1.4 拓展案例 2&#xff1a;使用缓存来避免重复请求 6.2 处理大规模数据爬取6.2.1 重点基础知识讲解…

新加坡大带宽服务器优势特点

随着互联网技术的不断进步&#xff0c;大带宽服务器在满足高速数据传输需求方面发挥着越来越重要的作用。新加坡&#xff0c;作为全球互联网基础设施的重要枢纽&#xff0c;其大带宽服务器在全球范围内备受关注。本文将深入探讨新加坡大带宽服务器的优势特点&#xff0c;以及如…

蓝桥杯每日一题----区间dp

前言 暂时没啥好说的&#xff0c;直接进入正题吧 引入 涂色PAINT 读题发现要求的是使一段区间满足要求的最小操作次数&#xff0c;考虑用动态规划去做。 第一步&#xff1a;考虑缩小规模&#xff0c;这里的规模其实就是区间长度&#xff0c;那么dp数组应该可以表示某个区间&…

白话 Transformer 原理-以 BERT 模型为例

白话 Transformer 原理-以 BERT 模型为例 第一部分:引入 1-向量 在数字化时代,数学运算最小单位通常是自然数字,但在 AI 时代,这个最小单元变成了向量,这是数字化时代计算和智能化时代最重要的差别之一。 举个例子:银行在放款前,需要评估一个人的信用度;对于用户而…

解析Python中HTTP代理的常见问题

在Python编程中&#xff0c;HTTP代理是一个经常被提及的概念&#xff0c;尤其在处理网络请求和爬虫时。但与此同时&#xff0c;使用HTTP代理也经常会遇到一些令人头疼的问题。接下来&#xff0c;就让我们一起解析一下Python中使用HTTP代理时常见的那些问题。 1. 代理服务器无响…

06、全文检索 -- Solr -- Solr 全文检索之在图形界面管理 Core 的 Schema(演示对 普通字段、动态字段、拷贝字段 的添加和删除)

目录 Solr 全文检索之管理 Schema使用Web控制台管理Core的Schema3 种 字段解释&#xff1a;Field&#xff1a;普通字段Dynamic Field&#xff1a;动态字段Copy Field&#xff1a;拷贝字段 演示&#xff1a;添加 普通字段&#xff08; Field &#xff09;演示&#xff1a;添加 动…

CSS写渐变边框线条

box-sizing: border-box; border-top: 1px solid; border-image: linear-gradient(to right, red, blue) 1;