lv14 led驱动设备树版本 13

led驱动代码中无法给其他开发板重用,编程依据不清晰,如下,修改后尽量在代码中不直接修改寄存器。

把编程依据写到设备树中

一、起源

减少垃圾代码

减轻驱动开发工作量

驱动代码和设备信息分离

参考Open Fireware设计

用来记录硬件平台中各种硬件设备的属性信息

二、基本组成

设备树文件一共两种源文件:

  1. xxxxx.dts dts是device tree source的缩写(类似于c语言中.c文件)

  2. xxxxx.dtsi dtsi是device tree source include的缩写,意味着这样源文件用于被dts文件包含用(类似于c语言中的.h文件)

实际使用时,需要把dts文件编译成对应的二进制文件(.dtb文件,dtb是device tree binary的缩写 )便于运行时存放在内存加快读取信息的速度

三、基本语法

  • dts文件主体内容由多个节点组成
  • 每个节点可以包含0或多个子节点,形成树状关系
  • 每个dts文件都有一个根节点,其它节点都是它的子孙
  • 根节点一般来描述整个开发板硬件平台,其它节点用来表示具体设备、总线的属性信息
  • 各个节点可以有多个属性,每个属性用key-value键值对来表示(节点即宏定义当开关用,有节点代表具备这种特性)

节点语法:

[label:] node-name[@unit-address] {    [properties definitions];    [child nodes];
};
label: 可选项,节点别名,为了缩短节点访问路径,后续节点中可以使用  &label 来表示引用指定节点
node-name: 节点名
unit-address: 设备地址,一般填写该设备寄存器组或内存块的首地址
properties definitions:属性定义
child nodes:子节点

属性语法:

[label:] property-name = value;
[label:] property-name;
属性可以无值
有值的属性,可以有三种取值:
1. arrays of cells(1个或多个32位数据, 64位数据使用2个32位数据表示,空格分隔),用尖括号表示(< >)
2. string(字符串), 用双引号表示(" ")
3. bytestring(1个或多个字节,空格分隔),用方括号表示([])
4. 用,分隔的多值

四、特殊节点

4.1 根节点

根节点表示整块开发板的信息

#address-cells   // 在子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells      // 在子节点的reg属性中, 使用多少个u32整数来描述大小(size)
compatible       // 哪些平台兼容性 定义一系列的字符串, 用来指定内核中哪个machine_desc可以支持本设备,即描述其兼容哪些平台                         
model            // 哪款板子 比如有2款板子配置基本一致, 它们的compatible是一样的,那么就通过model来分辨这2款板子

region(内存区域块大小) 

4.2 /memory

所有设备树文件的必需节点,它定义了系统物理内存的 layout。一般描述计算机的外接内存(SDRAM)多大,起始地址是多少。内部内存一般都有专门用途(SRAM ROM)

device_type = "memory";
reg             //用来指定内存的地址、大小

4.3 /chosen

传递内核启动时使用的参数parameter

bootargs  //字符串,内核启动参数, 跟u-boot中设置的bootargs作用一样

4.4 /cpus 多核CPU支持

/cpus节点下有1个或多个cpu子节点, cpu子节点中用reg属性用来标明自己是哪一个cpu

所以 /cpus 中有以下2个属性:

#address-cells   // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells      // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size) 必须设置为0

一般我们上面使用的都是soc芯片厂家的二次移植,作为修改。 

五、常用属性

我们自己来写,一般需要写属性来描述外设的起始地址、大小多大,中断号,GPIO引脚等。

5.1 phandle

数字形式的节点标识,在后续节点中属性值性质表示某节点时,可以引用对应节点

如:

pic@10000000 {    phandle = <1>;           //除了节点原名pic,节点别名,地址等,还可以使用节点标识来代表节点,数字不能重复interrupt-controller;
};
another-device-node {    interrupt-parent = <1>;   // 使用phandle值为1来引用上述节点
};

5.2 地址 --------------- 重要

reg属性:表示内存区域region,语法:

reg = <address1 length1 [address2 length2] [address3 length3]>;//                       第二个内存卡起始地址和大小  第三个内存卡起始地址和大小

#address-cells:reg属性中, 使用多少个u32整数来描述地址(address),语法:

#address-cells = <数字>;

#size-cells:reg属性中, 使用多少个u32整数来描述大小(size),语法:

#size-cells = <数字>;

5.3 compatible --------------- 重要

驱动和设备(设备节点)的匹配依据,compatible(兼容性)的值可以有不止一个字符串以满足不同的需求,语法:

compatible = "字符串1","字符串2",...;

在平台属性中还会介绍 

5.4 中断 --------------- 重要

a. 中断控制器节点用的属性:

interrupt-controller 一个无值空属性用来声明这个node接收中断信号,表示该节点是一个中断控制器

#interrupt-cells 这是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符

b. 中断源设备节点用的属性:

interrupt-parent:标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的,语法:

interrupt-parent = <引用某中断控制器节点>

interrupts 一个中断标识符列表,表示每一个中断输出信号,语法:

interrupts = <中断号 触发方式>
​
1 low-to-high 上升沿触发
2 high-to-low 下降沿触发
4 high level  高电平触发
8 low level   低电平触发

5.5 gpio --------------- 重要

gpio也是最常见的IO口,常用的属性有:

a. 对于GPIO控制器:

gpio-controller,无值空属性,用来说明该节点描述的是一个gpio控制器

#gpio-cells,用来表示要用几个cell描述一个 GPIO引脚

b. 对于GPIO使用者节点:

gpio使用节点的属性

xxx-gpio = <&引用GPIO控制器 GPIO标号 工作模式>
工作模式:
1 低电平有效 GPIO_ACTIVE_HIGH
0 高电平有效 GPIO_ACTIVE_LOW

5.6 属性设置套路

一般来说,每一种设备的节点属性设置都会有一些套路,比如可以设置哪些属性?属性值怎么设置?那怎么知道这些套路呢,有两种思路:

  1. 抄类似的dts,比如我们自己项目的平台是4412,那么就可以抄exynos4412-tiny4412.dts、exynos4412-smdk4412.dts这类相近的dts

  2. 查询内核中的文档,比如Documentation/devicetree/bindings/i2c/i2c-imx.txt就描述了imx平台的i2c属性设置方法;Documentation/devicetree/bindings/fb就描述了lcd、lvds这类属性设置方法

六、常用接口

struct device_node 对应设备树中的一个节点 struct property 对应节点中一个属性

6.1 of_find_node_by_path

/**
include/of.h
of_find_node_by_path - 通过路径查找指定节点
@path - 带全路径的节点名,也可以是节点的别名
成功:得到节点的首地址;失败:NULL
*/
struct device_node * of_find_node_by_path(const char *path);

of代表openfire

6.2 of_find_property

/*
include/of.h
of_find_property - 提取指定属性的值
@np - 设备节点指针
@name - 属性名称
@lenp - 属性值的字节数
成功:属性值的首地址;失败:NULL
*/
struct property *of_find_property(const struct device_node *np, const char *name, int *lenp);

6.3 of_get_named_gpio

/*** include/of_gpio.h* of_get_named_gpio - 从设备树中提取gpio口* @np - 设备节点指针* @propname - 属性名* @index - gpio口引脚标号 * 成功:得到GPIO口编号;失败:负数,绝对值是错误码*/
int of_get_named_gpio(struct device_node *np, const char *propname, int index);

6.4 irq_of_parse_and_map

/*功能:获得设备树中的中断号并进行映射参数:node:设备节点index:序号返回值:成功:中断号  失败:错误码
*/
unsigned int irq_of_parse_and_map(struct device_node *node, int index);

6.5 读属性值

of_property_read_string

/*
of_property_read_string - 提取字符串(属性值)
@np - 设备节点指针
@propname - 属性名称
@out_string - 输出参数,指向字符串(属性值)
成功:0;失败:负数,绝对值是错误码
*/
int of_property_read_string(struct device_node *np, const char *propname, const char **out_string);

读数值

int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value)
​
int of_property_read_u16(const struct device_node *np,const char *propname,u16 *out_value)
​
int of_property_read_u32(const struct device_node *np,const char *propname,u32 *out_value)

判断属性是否存在

int of_property_read_bool(const struct device_node *np,const char *propname)

读数组(如<>或者[])

int of_property_read_u32_array(const struct device_node *np,const char *propname,u32 *out_value,size_t sz)

七、GPIO接口

7.1 向内核申请GPIO

int gpio_request(unsigned gpio,const char *label)

功能:其实就是让内核检查一下该GPIO引脚是否被其它设备占用,如果没有占用则返回0并用label做一下标记,表示被本设备占用,否则返回负数

void gpio_free(unsigned gpio)

功能:去除本设备对该GPIO的占用标记,表示本设备向内核归还对该GPIO引脚的使用权,此后其它设备可占用该GPIO引脚

7.2 设置GPIO方向

int gpio_direction_input(unsigned gpio)int gpio_direction_output(unsigned gpio,int value)

7.3 读写GPIO数据

int gpio_get_value(unsigned gpio)int gpio_set_value(unsigned gpio,int value)

八、led驱动设备树版

  1. 在设备树源文件的根节点下添加本设备的节点(该节点中包含本设备用到的资源信息)

    ..../linux3.14/arch/arm/boot/dts/exynos4412-fs4412.dtsfs4412-leds {compatible = "fs4412,led2-5";   //兼容性led2-gpio = <&gpx2 7 0>;        //GPIO接口设置led3-gpio = <&gpx1 0 0>;led4-gpio = <&gpf3 4 0>;led5-gpio = <&gpf3 5 0>;
    };
  2. 在linux内核源码的顶层目录下执行:make dtbs (生成对应的dtb文件)

  3. cp ?????.dtb /tftpboot

  4. 编写驱动代码:

    a. 通过本设备在设备树中的路径找到对应节点(struct device_node类型的地址值)

    b. 调用 of_get_named_gpio 函数得到某个GPIO的编号(一般在init中完成)

    c. struct leddev结构体中记录所有用到的GPIO编号(一般在init中完成)

    d. 使用某个GPIO引脚前需先通过gpio_request函数向内核申请占用该引脚,不用该引脚时可通过gpio_free归还给内核(申请一般在init中完成,归还在exit中完成)

    e. 通过gpio_direction_input和gpio_direction_output函数来设置某个GPIO的作用(一般在init中完成)

    f. 通过gpio_get_value函数可以获取某个GPIO引脚的当前电平

    g. 通过gpio_set_value函数可以改变某个GPIO引脚的电平

九、编写led驱动

9.1 改写设备树

找到开发板之前对应的dts文件

在根节点下面增加设备树led信息

重新编译make dtbs,生成dtb并拷贝到tftp目录下 

 

 9.2 改写驱动

leddrv_dt.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>#include "leddrv.h"int major = 11;
int minor = 0;
int myled_num  = 1;//不会对寄存器直接操作,改为对设备编号操作
struct myled_dev
{struct cdev mydev;unsigned int led2gpio;unsigned int led3gpio;unsigned int led4gpio;unsigned int led5gpio;
};struct myled_dev *pgmydev = NULL;int myled_open(struct inode *pnode,struct file *pfile)
{pfile->private_data =(void *) (container_of(pnode->i_cdev,struct myled_dev,mydev));return 0;
}int myled_close(struct inode *pnode,struct file *pfile)
{return 0;
}void led_on(struct myled_dev *pmydev,int ledno)
{switch(ledno){case 2:gpio_set_value(pmydev->led2gpio,1);break;case 3:gpio_set_value(pmydev->led3gpio,1);break;case 4:gpio_set_value(pmydev->led4gpio,1);break;case 5:gpio_set_value(pmydev->led5gpio,1);break;}
}void led_off(struct myled_dev *pmydev,int ledno)
{switch(ledno){case 2:gpio_set_value(pmydev->led2gpio,0);break;case 3:gpio_set_value(pmydev->led3gpio,0);break;case 4:gpio_set_value(pmydev->led4gpio,0);break;case 5:gpio_set_value(pmydev->led5gpio,0);break;}
}long myled_ioctl(struct file *pfile,unsigned int cmd,unsigned long arg)
{struct myled_dev *pmydev = (struct myled_dev *)pfile->private_data;if(arg < 2 || arg > 5){return -1;}switch(cmd){case MY_LED_ON:led_on(pmydev,arg);break;case MY_LED_OFF:led_off(pmydev,arg);break;default:return -1;}return 0;
}struct file_operations myops = {.owner = THIS_MODULE,.open = myled_open,.release = myled_close,.unlocked_ioctl = myled_ioctl,
};//申请gpio编号,init中会调用
void request_leds_gpio(struct myled_dev *pmydev,struct device_node *pnode)
{pmydev->led2gpio = of_get_named_gpio(pnode,"led2-gpio",0);gpio_request(pmydev->led2gpio,"led2");pmydev->led3gpio = of_get_named_gpio(pnode,"led3-gpio",0);gpio_request(pmydev->led3gpio,"led3");pmydev->led4gpio = of_get_named_gpio(pnode,"led4-gpio",0);gpio_request(pmydev->led4gpio,"led4");pmydev->led5gpio = of_get_named_gpio(pnode,"led5-gpio",0);gpio_request(pmydev->led5gpio,"led5");
}void set_leds_gpio_output(struct myled_dev *pmydev)
{gpio_direction_output(pmydev->led2gpio,0);gpio_direction_output(pmydev->led3gpio,0);gpio_direction_output(pmydev->led4gpio,0);gpio_direction_output(pmydev->led5gpio,0);
}void free_leds_gpio(struct myled_dev *pmydev)
{gpio_free(pmydev->led2gpio);gpio_free(pmydev->led3gpio);gpio_free(pmydev->led4gpio);gpio_free(pmydev->led5gpio);
}int __init myled_init(void)
{int ret = 0;dev_t devno = MKDEV(major,minor);struct device_node *pnode = NULL;pnode = of_find_node_by_path("/fs4412-leds");if(NULL == pnode){printk("find node by path failed\n");return -1;}/*申请设备号*/ret = register_chrdev_region(devno,myled_num,"myled");if(ret){ret = alloc_chrdev_region(&devno,minor,myled_num,"myled");if(ret){printk("get devno failed\n");return -1;}major = MAJOR(devno);//容易遗漏,注意}pgmydev = (struct myled_dev *)kmalloc(sizeof(struct myled_dev),GFP_KERNEL);if(NULL == pgmydev){unregister_chrdev_region(devno,myled_num);printk("kmalloc failed\n");return -1;}memset(pgmydev,0,sizeof(struct myled_dev)); //这里的memset并非c库的函数,而是内核自己实现的memset函数/*给struct cdev对象指定操作函数集*/	cdev_init(&pgmydev->mydev,&myops);/*将struct cdev对象添加到内核对应的数据结构里*/pgmydev->mydev.owner = THIS_MODULE;cdev_add(&pgmydev->mydev,devno,myled_num);/*ioremap*/request_leds_gpio(pgmydev,pnode);/*con-register set output*/set_leds_gpio_output(pgmydev);return 0;
}void __exit myled_exit(void)
{dev_t devno = MKDEV(major,minor);/*iounmap*/free_leds_gpio(pgmydev);cdev_del(&pgmydev->mydev);unregister_chrdev_region(devno,myled_num);kfree(pgmydev);pgmydev = NULL;
}MODULE_LICENSE("GPL");module_init(myled_init);
module_exit(myled_exit);

查看头文件 

修改Makefile

ifeq ($(KERNELRELEASE),)ifeq ($(ARCH),arm)
KERNELDIR ?= /home/linux/Linux_4412/kernel/linux-3.14
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_installclean:rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versionselseCONFIG_MODULE_SIG=n
obj-m += mychar.o
obj-m += mychar_poll.o
obj-m += openonce_atomic.o
obj-m += openonce_spinlock.o
obj-m += mychar_sema.o
obj-m += mychar_mutex.o
obj-m += second.o
obj-m += leddrv.o
obj-m += leddrv_dt.oendif

编译 

拷贝ko文件到rootfs下

启动开发板insmod插入模块测试

 

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

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

相关文章

数据结构-->线性表-->单链表

链表的定义 链表&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 与顺序表不同的是&#xff0c;链表里的每节都是独立申请下来的空间&#xff0c;我们称之为“节点、结点”。 节点的组成主要由…

机器翻译后的美赛论文怎么润色

美赛论文的语言表达一直是组委会看重的点&#xff0c;清晰的思路和地道的语言在评审中是重要的加分项。 今天我们就来讲讲美赛论文的语言问题。 我相信有相当一部分队伍在打美赛的时候&#xff0c;出于效率的考量&#xff0c;都会选择先写中文论文&#xff0c;再机翻成英文。 …

ChatGPT4 教你如何完成SQL的实践应用

对数据库的各项应用与操作都离不开SQL来对数据进行增删改查。 例如 &#xff1a; 有一张某公司职员信息表如下&#xff1a; 需求1&#xff1a;在公司职员信息表中&#xff0c;请统计各部门&#xff0c;各岗位下的员工人数。 如果这个SQL语句不会写或者不知道怎么操作可以交给…

Linux运行级别 | 管理Linux服务

Linux运行级别 级别&#xff1a; 0关机1单用户2多用户但是不运行nfs网路文件系统3默认的运行级别&#xff0c;给一个黑的屏幕&#xff0c;只能敲命令4未使用5默认的运行级别&#xff0c;图形界面6重启切换运行级别&#xff1a; init x管理Linux服务 systemctl命令&#xf…

【北邮鲁鹏老师计算机视觉课程笔记】02 filter

1 图像的类型 二进制图像&#xff1a; 灰度图像&#xff1a; 彩色图像&#xff1a; 2 任务&#xff1a;图像去噪 噪声点让我们看得难受是因为噪声点与周边像素差别很大 3 均值 滤波核 卷积核 4 卷积操作 对应相乘再累加起来 卷积核记录了权值&#xff0c;把权值套到要卷积…

vivo发布2023 年度科技创新;阿里全新AI代理,可模拟人类操作手机

vivo 发布 2023 年度十大产品技术创新 近日&#xff0c;vivo 发布了「2023 年度科技创新」十大产品技术创新榜单&#xff0c;并将这些技术分为了 4 个板块。 「四大蓝科技」为 vivo 在去年推出的全新技术品牌&#xff0c;涵盖蓝晶芯片技术栈、蓝海续航系统、蓝心大模型、蓝河操…

基于springboot会员制医疗预约服务管理信息系统源码和论文

会员制医疗预约服务管理信息系统是针对会员制医疗预约服务管理方面必不可少的一个部分。在会员制医疗预约服务管理的整个过程中&#xff0c;会员制医疗预约服务管理系统担负着最重要的角色。为满足如今日益复杂的管理需求&#xff0c;各类的管理系统也在不断改进。本课题所设计…

sqlmap 使用笔记(kali环境)

sqlmap使用 kali环境 -u或–url 直接扫描单个路径 //如果需要登录要有cookie sqlmap -u "http://10.0.0.6:8080/vulnerabilities/sqli/?id1" --cookie"PHPSESSIDisgvp2rv4uts46jbkb9bouq6ir; securitylow"-m 文件中保存多个url&#xff0c;工具会依次扫…

93 log4j-slf4j-impl 搭配上 log4j-to-slf4j 导致的 StackOverflow

前言 呵呵 最近想要 做一个 mongo 低版本的客户端读取高版本的服务端传递过来的数据造成的一个错误的时候, 出现了这样的问题 引入了 mongo-java-driver 之后, 使用相关 api 的时候会触发 com.mongo.internal.connection.BaseCluser 的初始化, 其依赖的 Loggers 间接的依赖…

解决MapboxGL的Popup不支持HTMLDiv元素的问题

解决MapboxGL的Popup不支持HTMLDiv元素的问题 官网给出的文档是不支持HTMLDivElement的&#xff0c;只支持HTML标签。 如果单纯的只显示字符串&#xff0c;那就没问题&#xff0c;如果想在Popup中使用更强大的功能&#xff0c;此时就不行了&#xff0c;下面是源码的一部分显示…

python从入门到精通(十):python爬虫的BeautifulSoup4

python爬虫的BeautifulSoup4 BeautifulSoup4导入模块解析文件创建对象python解析器beautifulsoup对象的种类Tag获取整个标签获取标签里的属性和属性值Navigablestring 获取标签里的内容BeautifulSoup获取整个文档Comment输出的内容不包含注释符号BeautifulSoup文档遍历Beautifu…

金融信贷风控系统设计

前言 近一年多以来在金融行业负责风控系统&#xff0c;根据自己工作中的经验&#xff0c;写下这篇文章。既是对自己在风控领域工作的总结&#xff0c;也是给刚入行和准备入行的朋友打个样&#xff0c;希望能有所帮助。 为什么要有风控系统 记得 2016 年信贷行业的发展形势还…

JavaScript综合练习4

JavaScript 综合练习 4 1. 案例演示 2. 代码实现 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title&…

[职场] 如何通过运营面试_1 #笔记#媒体#经验分享

如何通过运营面试 盈利是公司的事情&#xff0c;而用户就是你运营的事情。你需要彻底建立一个庞大而有效的用户群&#xff0c;这样才能让你们的公司想盈利就盈利&#xff0c;想战略就战略&#xff0c;想融资就融资。 一般从事运营的人有着强大的自信心&#xff0c;后台数据分析…

M1 Mac使用SquareLine-Studio进行LVGL开发

背景 使用Gui-Guider开发遇到一些问题,比如组件不全。使用LVGL官方的设计软件开发 延续上一篇使用的基本环境。 LVGL项目 新建项目 选择Arduino的项目,设定好分辨率及颜色。 设计UI 导出代码 Export -> Create Template Project 导出文件如图 将libraries下的ui文…

微服务学习 | Spring Cloud 中使用 Sentinel 实现服务限流

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站https://www.captainbed.cn/kitie。 目录 前言 通过代码实现限流 定义资源 通过代码定义资源 通过注解方式定义资源 定义限流规则 通过…

第三章:光效果产生立体感

本文是《从0开始图形学》笔记的第三章&#xff0c;上一章中我们已经将箱子的整个形状“找出来”了&#xff0c;但是还仅仅只是一个色块区域。这一节我们就利用光将整个箱子的立体感凸显出来。涉及到布林冯光照模型以及向量的点乘运算。 概念解说 这里需要用到“布林冯”光照模…

C语言函数(三):数组和函数实现扫雷游戏

目录 1.扫雷游戏的分析和设计1.1.扫雷游戏的功能说明1.2.游戏的分析与设计1.2.1 数据结构的分析1.2.2 文件结构设计 2.扫雷游戏的代码实现 1.扫雷游戏的分析和设计 1.1.扫雷游戏的功能说明 使用控制台实现经典的扫雷游戏游戏可以通过菜单实现继续玩游戏或者退出游戏扫雷的棋盘…

网课:数独挑战——牛客(题解与疑问)

题目描述 数独是一种填数字游戏&#xff0c;英文名叫 Sudoku&#xff0c;起源于瑞士&#xff0c;上世纪 70 年代由美国一家数学逻辑游戏杂志首先发表&#xff0c;名为 Number Place&#xff0c;后在日本流行&#xff0c;1984 年将 Sudoku 命名为数独&#xff0c;即 “独立的数…

刘谦春晚纸牌魔术背后的数学—海明码原理简介

在昨天2024年的春晚舞台上&#xff0c;魔术大师刘谦以一场令人拍案叫绝的纸牌魔术再度震撼全场。他巧妙地利用了数学原理&#xff0c;精准无误地让观众“随机”选择的纸牌完成了配对&#xff0c;尤其是令人忍俊不禁的是主持人尼格买提的纸牌却没有如愿配对&#xff0c;小尼碎了…