当前位置: 首页 > news >正文

STM32MP157A单片机移植Linux驱动

在stm32mp157a单片机移植Linux操作系统,并移植内核驱动,在应用程序中使用3个线程,分别实现控制单片机上3个led流水灯的功能、蜂鸣器控制的功能、风扇控制的功能。

需求整理:

1.驱动程序-->led1.c,led2.c,led3.c,beep.c,fan.c。实现对led字符设备驱动的注册(register_chrdev)和注销(unregister_chrdev)功能、对字符设备相关操作方法的封装(用户空间和内核空间进行数据传递-->copy_to_user,copy_from_user)、物理内存映射虚拟内存(ioremap,iounmap),通过原理图可知---led1->PE10,led2->PF10,led3->PE8,beep->PB6,fan->PE9;

2.头文件-->led.h,beep.h,fan.h。物理内存的寄存器地址;

3.脚本文件生成驱动程序-->Makefile-->生成led1.ko,led2.ko,led3.ko,beep.ko,fan.ko;

4.流水灯应用程序-->application_test.c。使用3个线程实现对led流水灯的控制、蜂鸣器控制、风扇控制。

5.shell命令创建设备文件-->/dev/led1,/dev/led2,/dev/led3,/dev/beep,/dev/fan。用于流水灯应用程序对led的文件描述符。

分析:

仅使用open、write、read、close对io进行控制,直接在write对应的回调函数中进行数据处理,再此基础上实现多线程驱动的逻辑代码。

方案实现:
1.驱动程序
led1.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "led.h"//字符设备描述符
unsigned int major;
//接收数据buf
char myled1_buf[128] = {};
//虚拟映射寄存器地址
unsigned int* vir_rcc;
unsigned int* vir_moder;
unsigned int* vir_odr;int myled1_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
//
ssize_t myled1_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_from_user(myled1_buf, ubuf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}	//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);if (myled1_buf[0] == 1){(*vir_odr) |= (0x1<<10);	//高电平}else if (myled1_buf[0] == 0){(*vir_odr) &=  (~(0x1<<10));	//低电平}return 0;
}ssize_t myled1_read(struct file *file, char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_to_user(ubuf, myled1_buf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}int myled1_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
//定义字符设备的回调函数接口
struct file_operations fops = {.open    = myled1_open,  .read    = myled1_read,  .write   = myled1_write, .release = myled1_close,                                 
};//字符设备注册
static int __init myled1_init(void)
{major = register_chrdev(0, "myled1", &fops);if (major < 0){printk("字符设备注册失败\n");}printk("字符设备注册成功 major = %d\n", major);//硬件寄存器映射到虚拟寄存器地址 ioremapvir_rcc = ioremap(PHY_RCC_GPIO, 4);if (vir_rcc == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);return -1;}vir_moder = ioremap(PHY_GPIOE_MODER, 4);if (vir_moder == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);return -1;}vir_odr = ioremap(PHY_GPIOE_ODR, 4);if (vir_odr == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);iounmap(vir_moder);return -1;}printk("物理内存映射成功\n");//初始化PE10(*vir_rcc) |= (0x1<<4);	//使能rcc(*vir_moder) &= (~(0x3<<20));(*vir_moder) |= (0x1<<20);(*vir_odr) &=  (~(0x1<<10));//默认低电平return 0;
}
//字符设备注销
static void __exit myled1_exit(void)
{iounmap(vir_rcc);iounmap(vir_moder);iounmap(vir_odr);unregister_chrdev(major, "myled1");printk("字符设备注销成功\n");
}
//模块
module_init(myled1_init);
module_exit(myled1_exit);
//遵循GPL开源协议
MODULE_LICENSE("GPL");
led2.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "led.h"unsigned int major;
char myled2_buf[128] = {};
unsigned int* vir_rcc;
unsigned int* vir_moder;
unsigned int* vir_odr;int myled2_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
//
ssize_t myled2_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_from_user(myled2_buf, ubuf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}	//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);if (myled2_buf[0] == 1){(*vir_odr) |= (0x1<<10);	//高电平}else if (myled2_buf[0] == 0){(*vir_odr) &=  (~(0x1<<10));	//低电平}return 0;
}ssize_t myled2_read(struct file *file, char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_to_user(ubuf, myled2_buf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}int myled2_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}struct file_operations fops = {.open    = myled2_open,  .read    = myled2_read,  .write   = myled2_write, .release = myled2_close,                                 
};static int __init myled2_init(void)
{major = register_chrdev(0, "myled2", &fops);if (major < 0){printk("字符设备注册失败\n");}printk("字符设备注册成功 major = %d\n", major);//硬件寄存器映射到虚拟寄存器地址 ioremapvir_rcc = ioremap(PHY_RCC_GPIO, 4);if (vir_rcc == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);return -1;}vir_moder = ioremap(PHY_GPIOF_MODER, 4);if (vir_moder == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);return -1;}vir_odr = ioremap(PHY_GPIOF_ODR, 4);if (vir_odr == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);iounmap(vir_moder);return -1;}printk("物理内存映射成功\n");//初始化PF10(*vir_rcc) |= (0x1<<5);	//使能rcc(*vir_moder) &= (~(0x3<<20));(*vir_moder) |= (0x1<<20);(*vir_odr) &=  (~(0x1<<10));//默认低电平return 0;
}static void __exit myled2_exit(void)
{iounmap(vir_rcc);iounmap(vir_moder);iounmap(vir_odr);unregister_chrdev(major, "myled2");printk("字符设备注销成功\n");
}module_init(myled2_init);
module_exit(myled2_exit);
MODULE_LICENSE("GPL");
 led3.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "led.h"unsigned int major;
char myled3_buf[128] = {};
unsigned int* vir_rcc;
unsigned int* vir_moder;
unsigned int* vir_odr;int myled3_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
//
ssize_t myled3_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_from_user(myled3_buf, ubuf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}	//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);if (myled3_buf[0] == 1){(*vir_odr) |= (0x1<<8);	//高电平}else if (myled3_buf[0] == 0){(*vir_odr) &=  (~(0x1<<8));	//低电平}return 0;
}ssize_t myled3_read(struct file *file, char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_to_user(ubuf, myled3_buf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}int myled3_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}struct file_operations fops = {.open    = myled3_open,  .read    = myled3_read,  .write   = myled3_write, .release = myled3_close,                                 
};static int __init myled3_init(void)
{major = register_chrdev(0, "myled3", &fops);if (major < 0){printk("字符设备注册失败\n");}printk("字符设备注册成功 major = %d\n", major);//硬件寄存器映射到虚拟寄存器地址 ioremapvir_rcc = ioremap(PHY_RCC_GPIO, 4);if (vir_rcc == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);return -1;}vir_moder = ioremap(PHY_GPIOE_MODER, 4);if (vir_moder == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);return -1;}vir_odr = ioremap(PHY_GPIOE_ODR, 4);if (vir_odr == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);iounmap(vir_moder);return -1;}printk("物理内存映射成功\n");//初始化PE8(*vir_rcc) |= (0x1<<4);	//使能rcc(*vir_moder) &= (~(0x3<<16));(*vir_moder) |= (0x1<<16);(*vir_odr) &=  (~(0x1<<8));//默认低电平return 0;
}static void __exit myled3_exit(void)
{iounmap(vir_rcc);iounmap(vir_moder);iounmap(vir_odr);unregister_chrdev(major, "myled3");printk("字符设备注销成功\n");
}module_init(myled3_init);
module_exit(myled3_exit);
MODULE_LICENSE("GPL");
beep.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "beep.h"unsigned int major;
char mybeep_buf[128] = {};
unsigned int* vir_rcc;
unsigned int* vir_moder;
unsigned int* vir_odr;int mybeep_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
//
ssize_t mybeep_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_from_user(mybeep_buf, ubuf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}		printk("%s:%s:%d:mybeep_buf=%d\n", __FILE__, __func__, __LINE__, mybeep_buf[0]);if (mybeep_buf[0] == 1){(*vir_odr) |= (0x1<<6);	//高电平}else if (mybeep_buf[0] == 0){(*vir_odr) &=  (~(0x1<<6));	//低电平}return 0;
}ssize_t mybeep_read(struct file *file, char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_to_user(ubuf, mybeep_buf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}//printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}int mybeep_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
} struct file_operations fops = {.open    = mybeep_open,  .read    = mybeep_read,  .write   = mybeep_write, .release = mybeep_close,    
};static int __init mybeep_init(void)
{major = register_chrdev(0, "mybeep", &fops);if (major < 0){printk("字符设备注册失败\n");}printk("字符设备注册成功 major = %d\n", major);//硬件寄存器映射到虚拟寄存器地址 ioremapvir_rcc = ioremap(PHY_RCC_GPIO, 4);if (vir_rcc == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);return -1;}vir_moder = ioremap(PHY_GPIOB_MODER, 4);if (vir_moder == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);return -1;}vir_odr = ioremap(PHY_GPIOB_ODR, 4);if (vir_odr == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);iounmap(vir_moder);return -1;}printk("物理内存映射成功\n");//初始化PB6(*vir_rcc) |= (0x1<<1);	//使能rcc(*vir_moder) &= (~(0x3<<12));(*vir_moder) |= (0x1<<12);(*vir_odr) &=  (~(0x1<<6));//默认低电平return 0;
}static void __exit mybeep_exit(void)
{iounmap(vir_rcc);iounmap(vir_moder);iounmap(vir_odr);unregister_chrdev(major, "mybeep");printk("字符设备注销成功\n");
}module_init(mybeep_init);
module_exit(mybeep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Johnson");
MODULE_DESCRIPTION("A simple Linux char driver for beep control");
MODULE_VERSION("1.0");
fan.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "fan.h"unsigned int major;
char myfan_buf[128] = {};
unsigned int* vir_rcc;
unsigned int* vir_moder;
unsigned int* vir_odr;int myfan_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
//
ssize_t myfan_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_from_user(myfan_buf, ubuf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}	printk("%s:%s:%d:myfan_buf[0]=%d\n", __FILE__, __func__, __LINE__, myfan_buf[0]);if (myfan_buf[0] == 1){(*vir_odr) |= (0x1<<9);	//高电平}else if (myfan_buf[0] == 0){(*vir_odr) &=  (~(0x1<<9));	//低电平}return 0;
}ssize_t myfan_read(struct file *file, char __user *ubuf, size_t size, loff_t *lft)
{unsigned long n = copy_to_user(ubuf, myfan_buf, size);if (n > 0){printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return n;}printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}int myfan_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}struct file_operations fops = {.open    = myfan_open,  .read    = myfan_read,  .write   = myfan_write, .release = myfan_close,                                 
};static int __init myfan_init(void)
{major = register_chrdev(0, "myfan", &fops);if (major < 0){printk("字符设备注册失败\n");}printk("字符设备注册成功 major = %d\n", major);//硬件寄存器映射到虚拟寄存器地址 ioremapvir_rcc = ioremap(PHY_RCC_GPIO, 4);if (vir_rcc == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);return -1;}vir_moder = ioremap(PHY_GPIOE_MODER, 4);if (vir_moder == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);return -1;}vir_odr = ioremap(PHY_GPIOE_ODR, 4);if (vir_odr == NULL){printk("硬件寄存器映射失败:%d\n", __LINE__);iounmap(vir_rcc);iounmap(vir_moder);return -1;}printk("物理内存映射成功\n");//初始化PE9(*vir_rcc) |= (0x1<<4);	//使能rcc(*vir_moder) &= (~(0x3<<18));(*vir_moder) |= (0x1<<18);(*vir_odr) &=  (~(0x1<<9));//默认低电平return 0;
}static void __exit myfan_exit(void)
{iounmap(vir_rcc);iounmap(vir_moder);iounmap(vir_odr);unregister_chrdev(major, "myfan");printk("字符设备注销成功\n");
}module_init(myfan_init);
module_exit(myfan_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Johnson");
MODULE_DESCRIPTION("A simple Linux char driver for fan control");
MODULE_VERSION("1.0");
2.头文件

由于都是控制GPIO,使能相同的RCC时钟,为便利这里分为3个头文件。

led.h
#ifndef __LED_H__
#define __LED_H__#define PHY_RCC_GPIO	0x50000a28
#define PHY_GPIOE_MODER	0X50006000
#define PHY_GPIOE_ODR	0X50006014
#define PHY_GPIOF_MODER 0x50007000
#define PHY_GPIOF_ODR	0x50007014#endif
beep.h
#ifndef __BEEP_H__
#define __BEEP_H__#define PHY_RCC_GPIO	0x50000a28
#define PHY_GPIOB_MODER	0X50003000
#define PHY_GPIOB_ODR	0X50003014#endif
fan.h
#ifndef __FAN_H__
#define __FAN_H__#define PHY_RCC_GPIO	0x50000a28
#define PHY_GPIOE_MODER	0X50006000
#define PHY_GPIOE_ODR	0X50006014#endif
3.Makefile
Makefile
modname ?= led
arch ?= arm
ifeq ($(arch),arm)
KERNELDIR := ~/FSMP1A/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/linux-5.4.31/
else
KERNELDIR := /lib/modules/$(shell uname -r)/build/
endifPWD := $(shell pwd)all:make -C $(KERNELDIR) M=$(PWD) modulesobj-m = $(modname).o
#obj-m = demo.oclean:make -C $(KERNELDIR) M=$(PWD) clean
4.应用程序
application_test.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>char buf[5] = {};void* led_control(void* args)
{char led1_buf[1] = {};char led2_buf[1] = {};char led3_buf[1] = {};int fd1 = open("/dev/myled1", O_RDWR);if (fd1 < 0){perror("/dev/myled1");pthread_exit(NULL); return 0;}int fd2 = open("/dev/myled2", O_RDWR);if (fd2 < 0){perror("/dev/myled2");close(fd1);pthread_exit(NULL); return 0; }int fd3 = open("/dev/myled3", O_RDWR);if (fd3 < 0){perror("/dev/myled3");close(fd1);close(fd2);pthread_exit(NULL); return 0;}while(1){led1_buf[0] = buf[0];led2_buf[0] = buf[1];led3_buf[0] = buf[2];write(fd1, led1_buf, sizeof(led1_buf));write(fd2, led2_buf, sizeof(led2_buf));write(fd3, led3_buf, sizeof(led3_buf));sleep(1);}close(fd1);close(fd2);close(fd3);pthread_exit(NULL); return 0;
}void* beep_control(void* args)
{char beep_buf[1] = {};int fd1 = open("/dev/mybeep", O_RDWR);if (fd1 < 0){perror("/dev/mybeep");pthread_exit(NULL); return 0;}while(1){beep_buf[0] = buf[3];write(fd1, beep_buf, sizeof(beep_buf));sleep(1);}close(fd1);pthread_exit(NULL); return 0;
}void* fan_control(void* args)
{char fan_buf[1] = {};int fd1 = open("/dev/myfan", O_RDWR);if (fd1 < 0){perror("/dev/myfan");pthread_exit(NULL); return 0;}while(1){fan_buf[0] = buf[4];write(fd1, fan_buf, sizeof(fan_buf));sleep(1);}close(fd1);pthread_exit(NULL); return 0;
}void* main_control(void* args)
{int module, control;while(1){printf("请选择控制的模块:1(led1)2(led2)3(led3)4(beep)5(fan)>");scanf("%d", &module);if (module != 1 && module != 2 && module != 3 && module != 4 && module != 5){printf("模块[%d]不存在\n", module);}switch(module){case 1:printf("模块[%d]请选择开灯(1)或关灯(0)>", module);scanf("%d", &control);if (control != 0 && control != 1){printf("输入错误,请重新选择\n");break;}buf[0] = control;break;case 2:printf("模块[%d]请选择开灯(1)或关灯(0)>", module);scanf("%d", &control);if (control != 0 && control != 1){printf("输入错误,请重新选择\n");break;}buf[1] = control;break;case 3:printf("模块[%d]请选择开灯(1)或关灯(0)>", module);scanf("%d", &control);if (control != 0 && control != 1){printf("输入错误,请重新选择\n");break;}buf[2] = control;break;case 4:printf("模块[%d]请选择蜂鸣器响(1)或灭(0)>", module);scanf("%d", &control);if (control != 0 && control != 1){printf("输入错误,请重新选择\n");break;}buf[3] = control;break;case 5:printf("模块[%d]请选择风扇开(1)或关(0)>", module);scanf("%d", &control);if (control != 0 && control != 1){printf("输入错误,请重新选择\n");break;}buf[4] = control;break;default:break;}sleep(1);}pthread_exit(NULL); return 0;
}int main(int argc, char const *argv[])
{pthread_t threadled, threadbeep, threadfan, threadmain;int thread_led = 10;int thread_beep = 10;int thread_fan = 10;int thread_main = 10;if (pthread_create(&threadled , NULL, led_control, &thread_led) != 0){perror("pthread_create");exit(EXIT_FAILURE);}if (pthread_create(&threadbeep , NULL, beep_control, &thread_beep) != 0){perror("pthread_create");exit(EXIT_FAILURE);}if (pthread_create(&threadfan , NULL, fan_control, &thread_fan) != 0){perror("pthread_create");exit(EXIT_FAILURE);}if (pthread_create(&threadmain , NULL, main_control, &thread_main) != 0){perror("pthread_create");exit(EXIT_FAILURE);}if (pthread_join(threadled, NULL) != 0){perror("pthread_join");exit(EXIT_FAILURE);}if (pthread_join(threadbeep, NULL) != 0){perror("pthread_join");exit(EXIT_FAILURE);}if (pthread_join(threadfan, NULL) != 0){perror("pthread_join");exit(EXIT_FAILURE);}if (pthread_join(threadmain, NULL) != 0){perror("pthread_join");exit(EXIT_FAILURE);}// 主线程退出return 0;
}
5.mknod创建字符设备文件

mknod 字符设备文件名 字符设备类型(c/b) 主设备号 次设备号

mknod /dev/led1 c 主设备号 次设备号

mknod /dev/led2 c 主设备号 次设备号

mknod /dev/led3 c 主设备号 次设备号

mknod /dev/beep c 主设备号 次设备号

mknod /dev/fan c 主设备号 次设备号

在终端执行以上命令创建字符设备文件,否则在应用程序中open无法正常打开字符设备,导致线程退出。

相关文章:

STM32MP157A单片机移植Linux驱动

在stm32mp157a单片机移植Linux操作系统&#xff0c;并移植内核驱动&#xff0c;在应用程序中使用3个线程&#xff0c;分别实现控制单片机上3个led流水灯的功能、蜂鸣器控制的功能、风扇控制的功能。 需求整理&#xff1a; 1.驱动程序-->led1.c&#xff0c;led2.c&#xff…...

Qt程序退出相关资源释放问题

目录 问题背景&#xff1a; aboutToQuit 代码举例 closeEvent事件 代码举例 程序退出方式 quit() exit(int returnCode 0) close() 问题背景&#xff1a; 实际项目中程序退出前往往需要及进行一些资源释放、配置保存、线程中断等操作&#xff0c;避免资源浪费&#xff…...

【大学生职业规划大赛备赛PPT资料PDF | 免费共享】

自取链接&#xff1a; 链接&#xff1a;https://pan.quark.cn/s/4fa45515325e &#x1f4e2; 同学&#xff0c;你是不是正在为职业规划大赛发愁&#xff1f; 想展示独特思路却不知如何下手&#xff1f; 想用专业模板却找不到资源&#xff1f; 别担心&#xff01;我整理了全网…...

win32汇编环境,对话框中使用菜单示例一

;运行效果 ;win32汇编环境,对话框中使用菜单示例一 ;最基本的应用&#xff0c;即添加菜单及点击后响应的操作方法 ;直接抄进RadAsm可编译运行。重要部分加备注。 ;下面为asm文件 ;>>>>>>>>>>>>>>>>>>>>>>&g…...

AutoDock CrankPep or ADCP进行蛋白质多肽对接

需求描述 使用AutoDock CrankPep or ADCP进行蛋白质多肽对接 硬件及系统配置 自用电脑型号如下&#xff1a; 电脑&#xff1a;Precision Tower 7810 (Dell Inc.) CPU &#xff1a; Intel Xeon CPU E5-2686 v4 2.30GHz GPU&#xff1a; NVIDIA GeForce GTX 1070 Linux版本&a…...

高压直流熔断器研究

1.1 定义与作用 高压直流熔断器是一种用于直流电路的过电流保护装置&#xff0c;其主要作用是在电路中检测到过载电流或短路电流时&#xff0c;迅速切断电路&#xff0c;以防止电力设备受损或发生火灾等事故。根据 ISO-8820 和 QC/T420-2004 等标准的定义&#xff0c;熔断器是…...

微信小程序(uni)+蓝牙连接+Xprint打印机实现打印功能

1.蓝牙列表实现&#xff0c;蓝牙设备展示&#xff0c;蓝牙连接 <template><view class"container"><view class"container_top"><view class"l">设备名称</view><view class"r">{{state.phoneNam…...

使用 Docker 部署 Flask 应用

使用 Docker 部署 Flask 应用 一、引言 在现代软件开发中,应用的部署和环境管理是至关重要的环节。传统的部署方式常常会遇到 “在我机器上能运行,在你机器上不行” 的问题,而 Docker 的出现很好地解决了这个痛点。Docker 是一个用于开发、部署和运行应用程序的开放平台,…...

深入浅出GraphQL:现代API设计的未来

文章目录 一、引言二、什么是GraphQL&#xff1f;三、GraphQL的优势3.1 精确获取数据3.2 强类型系统3.3 单一端点3.4 实时数据 四、实际应用4.1 定义Schema4.2 实现解析器4.3 启动GraphQL服务器 五、结论 一、引言 在当今的 Web 开发中&#xff0c;API&#xff08;应用程序编程…...

深入理解Zookeeper:分布式系统的协调者

引言 在现代分布式系统中&#xff0c;协调和管理多个节点之间的状态和行为是一个复杂且关键的任务。Zookeeper作为一个分布式协调服务&#xff0c;为开发者提供了一种高效、可靠的方式来处理分布式系统中的一致性问题。本文将介绍Zookeeper的基本概念、使用场景以及如何通过示…...

python绘图之回归拟合图

回归拟合图在数据分析中具有重要作用&#xff0c;它不仅可以帮助我们理解变量之间的关系&#xff0c;还可以评估模型的拟合效果、进行预测和推断、发现异常值&#xff0c;以及用于模型比较和结果展示。 import pandas as pd import seaborn as sns import matplotlib.pyplot as…...

C语言学习笔记(第二部份)

说明&#xff1a;由于所有内容放在一个md文件中会非常卡顿&#xff0c;本文件将接续C.md文件的第二部分 结构体 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量。 结构体的成员可以是标量&#xff0c;数组&#xff0c;指针&#xff0c…...

jQuery UI CSS 框架 API

jQuery UI CSS 框架 API 概述 jQuery UI 是一个基于 jQuery 的用户界面和交互库,它提供了一套丰富的交互组件和视觉效果,旨在帮助开发者快速构建具有吸引力和互动性的网页应用。jQuery UI CSS 框架 API 是 jQuery UI 的一部分,它允许开发者通过简单的 CSS 类来控制 UI 组件…...

Redis7——基础篇(六)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09;Redis&#xff08;二&#xff09;Redis&#xff08;三&#xff09;Redis&#x…...

Windows网络安全基础

随着互联网的发展和普及&#xff0c;Windows网络安全问题愈发严重。在本文中&#xff0c;我们将会介绍Windows网络安全的基本概念&#xff0c;包括网络攻击类型、网络安全威胁、网络安全防御措施等等&#xff0c;帮助初学者更好地了解Windows网络安全。 一、网络攻击类型 网络…...

spring boot知识点4

1.如何监视所有spring boot微服务 安装actuator插件&#xff0c;然后通过接口查询 /actuator/health 2.spring boot项目性能如何优化 a.优化启动时间&#xff0c;去除重复的依赖 b.JVM优化&#xff08;java虚拟机优化&#xff09;&#xff0c;限制堆的最小最大值 c.数据库…...

【大模型系列篇】DeepSeek-R1如何通过强化学习有效提升大型语言模型的推理能力?

如何通过强化学习&#xff08;RL&#xff09;有效提升大型语言模型&#xff08;LLM&#xff09;的推理能力&#xff1f; 《DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning》由DeepSeek-AI团队撰写&#xff0c;主要介绍了他们开发的第一代…...

主表增一个子表批量新增

1、在新增接口里&#xff0c;先随机生成编码&#xff0c;生成RedisLock&#xff0c;逻辑校验&#xff0c;Dto转bean&#xff0c;新增主表&#xff0c;获取主表的ID&#xff0c;新增子表&#xff0c;最后释放锁 2、在修改接口里&#xff0c;获取主表ID&#xff0c;先修改主表&am…...

Llama 3.1 本地电脑部署 Linux系统 【轻松简易】

本文分享在自己的本地电脑部署 llama3.1&#xff0c;而且轻松简易&#xff0c;快速上手。 这里借助Ollama工具&#xff0c;在Linux系统中进行大模型部署~ Llama3.1&#xff0c;有三个版本&#xff1a;8B、70B、405B Llama 3.1 405B 是第一个公开可用的模型&#xff0c;在常识…...

langchain系列 - FewShotPromptTemplate 少量示例

导读 环境&#xff1a;OpenEuler、Windows 11、WSL 2、Python 3.12.3 langchain 0.3 背景&#xff1a;前期忙碌的开发阶段结束&#xff0c;需要沉淀自己的应用知识&#xff0c;过一遍LangChain 时间&#xff1a;20250220 说明&#xff1a;技术梳理&#xff0c;针对FewShotP…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...