Linux学习笔记————C 语言版 LED 灯实验

这里写目录标题

  • 一、实验程序编写
  • 二、 汇编部分实验程序编写
  • 三、C 语言部分实验程序编写
  • 四、编译下载验证

汇编 LED 灯实验中,我们讲解了如何使用汇编来编写 LED 灯驱动,实际工作中是很少用到汇编去写嵌入式驱动的,毕竟汇编太难,而且写出来也不好理解,大部分情况下都是使用 C 语言去编写的。只是在开始部分用汇编来初始化一下 C 语言环境,比如初始化 DDR、设置堆栈指针 SP 等等,当这些工作都做完以后就可以进入 C 语言环境,也就是运行 C 语言代码,一般都是进入 main 函数。所以我们有两部分文件要做:
①、汇编文件
汇编文件只是用来完成 C 语言环境搭建。
②、C 语言文件
C 语言文件就是完成我们的业务层代码的,其实就是我们实际例程要完成的功能。

一、实验程序编写

新建 VScode 工程,工程名字为“ledc”,新建三个文件:start.S、main.c 和 main.h。其中 start.S是汇编文件,main.c 和 main.h 是 C 语言相关文件

二、 汇编部分实验程序编写

示例代码  start.s 文件代码
描述 : I.MX6U-ALPHA/I.MX6ULL 开发板启动文件,完成 C 环境初始化,
 C 环境初始化完成以后跳转到 C 代码。
**************************************************************/
1 .global _start /* 全局标号 */
2 
3 /*
4 * 描述: _start 函数,程序从此函数开始执行,此函数主要功能是设置 C 5 * 运行环境。
6 */
7 _start: 
8
9 /* 进入 SVC 模式 */
10 mrs r0, cpsr
11 bic r0, r0, #0x1f /* 将 r0 的低 5 位清零,也就是 cpsr 的 M0~M4 */
12 orr r0, r0, #0x13 /* r0 或上 0x13,表示使用 SVC 模式 */
13 msr cpsr, r0 /* 将 r0 的数据写入到 cpsr_c 中 */
14
15 ldr sp, =0X80200000 /* 设置栈指针 */
16 b main /* 跳转到 main 函数 */


第 1 行定义了一个全局标号_start

第 7 行就是标号_start 开始的地方,相当于是一个_start 函数,这个_start 就是第一行代码。

第 10~ 13 行就是设置处理器进入 SVC 模式, Cortex-A 有九个运行模型,这里我们设置处理器运行在 SVC 模式下。处理器模式的设置是通过修改 CPSR(程序状态)寄存器来完成的, CPSR 寄存器中 M[4:0](CPSR 的 bit[4:0])就是设置处理器运行模式的,如果要将处理器设置为 SVC 模式,那么 M[4:0]就要等于 0X13。11~13 行代码就是先使用指令 MRS 将 CPSR寄存器的值读取到 R0 中,然后修改 R0 中的值,设置 R0 的 bit[4:0]为 0X13,然后再使用指令MSR 将修改后的 R0 重新写入到 CPSR 中。

第 15 行通过 ldr 指令设置 SVC 模式下的 SP 指针=0X80200000,因为 I.MX6U-ALPHA 开发板上的 DDR3 地址范围是 0X80000000~ 0XA0000000(512MB) 或 者0X80000000~ 0X90000000(256MB),不管是 512MB 版本还是 256MB 版本的,其 DDR3 起始地址都是 0X80000000。由于 Cortex-A7 的堆栈是向下增长的,所以将 SP 指针设置为 0X80200000,因此 SVC 模式的栈大小 0X80200000-0X80000000=0X200000=2MB,2MB 的栈空间已经很大了,如果做裸机开发的话绰绰有余。

第 16 行就是跳转到 main 函数,main 函数就是 C 语言代码了。

至此汇编部分程序执行完成,就几行代码,用来设置处理器运行到 SVC 模式下、然后初始化 SP 指针、最终跳转到 C 文件的 main 函数中。如果有玩过三星的 S3C2440 或者 S5PV210 的话会知道我们在使用 SDRAM 或者 DDR 之前必须先初始化 SDRAM 或者 DDR。所以 S3C2440或者 S5PV210 的汇编文件里面是一定会有 SDRAM 或者 DDR 初始化代码的。我们上面编写的start.s 文件中却没有初始化 DDR3 的代码,但是却将 SVC 模式下的 SP 指针设置到了 DDR3 的地址范围中,这不会出问题吗?肯定不会的,DDR3 肯定是要初始化的,但是不需要在 start.s 文件中完成。在分析 DCD 数据的时候就已经讲过了,DCD 数据包含了 DDR 配置参数,I.MX6U 内部的 Boot ROM 会读取 DCD 数据中的 DDR 配置参数然后完成 DDR 初始化的。

三、C 语言部分实验程序编写

C 语言部分有两个文件 main.c 和 main.h,main.h 里面主要是定义的寄存器地址,在 main.h里面输入代码:

示例代码 main.h 文件代码
#ifndef __MAIN_H
#define __MAIN_H
/******************************************************************
描述 : 时钟 GPIO1_IO03 相关寄存器地址定义。
其他 : 无
*****************************************************************/
1 /* 
2 * CCM 相关寄存器地址
3 */
4 #define CCM_CCGR0 *((volatile unsigned int *)0X020C4068)
5 #define CCM_CCGR1 *((volatile unsigned int *)0X020C406C) 
6 #define CCM_CCGR2 *((volatile unsigned int *)0X020C4070) 
7 #define CCM_CCGR3 *((volatile unsigned int *)0X020C4074) 
8 #define CCM_CCGR4 *((volatile unsigned int *)0X020C4078) 
9 #define CCM_CCGR5 *((volatile unsigned int *)0X020C407C)
10 #define CCM_CCGR6 *((volatile unsigned int *)0X020C4080)
11
12 /* 
13 * IOMUX 相关寄存器地址
14 */
15 #define SW_MUX_GPIO1_IO03 *((volatile unsigned int *)0X020E0068) 
16 #define SW_PAD_GPIO1_IO03 *((volatile unsigned int *)0X020E02F4) 
17
18 /* 
19 * GPIO1 相关寄存器地址
20 */
21 #define GPIO1_DR *((volatile unsigned int *)0X0209C000)
22 #define GPIO1_GDIR *((volatile unsigned int *)0X0209C004)
23 #define GPIO1_PSR *((volatile unsigned int *)0X0209C008)
24 #define GPIO1_ICR1 *((volatile unsigned int *)0X0209C00C)
25 #define GPIO1_ICR2 *((volatile unsigned int *)0X0209C010)
26 #define GPIO1_IMR *((volatile unsigned int *)0X0209C014)
27 #define GPIO1_ISR *((volatile unsigned int *)0X0209C018)
28 #define GPIO1_EDGE_SEL *((volatile unsigned int *)0X0209C01C)
29
30 #endif


在 main.h 中我们以宏定义的形式定义了要使用到的所有寄存器,后面的数字就是其地址,比如 CCM_CCGR0 寄存器的地址就是 0X020C4068,这个很简单,很好理解。

接下看一下 main.c 文件,在 main.c 里面输入如下所示代码:

示例代码 main.c 文件代码
/**************************************************************
描述 : I.MX6U 开发板裸机实验 2 C 语言点灯
使用 C 语言来点亮开发板上的 LED 灯,学习和掌握如何用 C 语言来
 完成对 I.MX6U 处理器的 GPIO 初始化和控制。
**************************************************************/
1 #include "main.h"
2 
3 /*
4 * @description : 使能 I.MX6U 所有外设时钟
5 * @param : 无 
6 * @return : 无 
7 */
8 void clk_enable(void) 
9 {
10 CCM_CCGR0 = 0xffffffff;
11 CCM_CCGR1 = 0xffffffff;
12 CCM_CCGR2 = 0xffffffff;
13 CCM_CCGR3 = 0xffffffff;
14 CCM_CCGR4 = 0xffffffff;
15 CCM_CCGR5 = 0xffffffff;
16 CCM_CCGR6 = 0xffffffff;
17 }
18
19 /*
20 * @description : 初始化 LED 对应的 GPIO
21 * @param : 无
22 * @return : 无
23 */
24 void led_init(void)
25 {
26 /* 1、初始化 IO 复用, 复用为 GPIO1_IO03 */
27 SW_MUX_GPIO1_IO03 = 0x5; 
28 
29 /* 2、配置 GPIO1_IO03 的 IO 属性 
30 *bit [16]:0 HYS 关闭
31 *bit [15:14]: 00 默认下拉
32 *bit [13]: 0 kepper 功能
33 *bit [12]: 1 pull/keeper 使能
34 *bit [11]: 0 关闭开路输出
35 *bit [7:6]: 10 速度 100Mhz
36 *bit [5:3]: 110 R0/6 驱动能力
37 *bit [0]: 0 低转换率
38 */
39 SW_PAD_GPIO1_IO03 = 0X10B0; 
40
41 /* 3、初始化 GPIO, GPIO1_IO03 设置为输出 */
42 GPIO1_GDIR = 0X0000008;
43 
44 /* 4、设置 GPIO1_IO03 输出低电平,打开 LED0 */
45 GPIO1_DR = 0X0;
46 }
48 /*
49 * @description : 打开 LED 灯
50 * @param : 无
51 * @return : 无
52 */
53 void led_on(void)
54 {
55 /* 
56 * 将 GPIO1_DR 的 bit3 清零 
57 */
58 GPIO1_DR &= ~(1<<3);
59 }
60 
61 /*
62 * @description : 关闭 LED 灯
63 * @param : 无
64 * @return : 无
65 */
66 void led_off(void)
67 {
68 /* 
69 * 将 GPIO1_DR 的 bit3 置 1
70 */
71 GPIO1_DR |= (1<<3);
72 }
73 
74 /*
75 * @description : 短时间延时函数
76 * @param - n : 要延时循环次数(空操作循环次数,模式延时)
77 * @return : 无
78 */
79 void delay_short(volatile unsigned int n)
80 {
81 while(n--){}
82 }
83 
84 /*
85 * @description : 延时函数,在 396Mhz 的主频下延时时间大约为 1ms
86 * @param - n : 要延时的 ms 数
87 * @return : 无
88 */
89 void delay(volatile unsigned int n)
90 {
91 while(n--)
92 {
93 delay_short(0x7ff);
94 }
95 }
96 
97 /*
98 * @description : main 函数
99 * @param : 无
100 * @return : 无
101 */
102 int main(void)
103 {
104 clk_enable(); /* 使能所有的时钟 */
105 led_init(); /* 初始化 led */
106
107 while(1) /* 死循环 */
108 { 
109 led_off(); /* 关闭 LED */
110 delay(500); /* 延时大约 500ms */
111
112 led_on(); /* 打开 LED */
113 delay(500); /* 延时大约 500ms */
114 }
115
116 return 0;
117 }

main.c 文件里面一共有 7 个函数,这 7 个函数都很简单。clk_enable 函数是使能CCGR0~CCGR6 所控制的所有外设时钟。led_init 函数是初始化 LED 灯所使用的 IO,包括设置IO 的复用功能、IO 的属性配置和 GPIO 功能,最终控制 GPIO 输出低电平来打开 LED 灯。led_on 和 led_off 这两个函数看名字就知道,用来控制 LED 灯的亮灭的。delay_short()和 delay()这两个函数是延时函数,delay_short()函数是靠空循环来实现延时的,delay()是对 delay_short()的 简单封 装, 在 I.MX6U 工 作在 396MHz(Boot ROM 设置 的 396MHz) 的主 频的时 候
delay_short(0x7ff)基本能够实现大约 1ms 的延时,所以 delay()函数我们可以用来完成 ms 延时。main 函数就是我们的主函数了,在 main 函数中先调用函数 clk_enable()和 led_init()来完成时钟使能和 LED 初始化,最终在 while(1)循环中实现 LED 循环亮灭,亮灭时间大约是 500ms。

本实验的程序部分就是这些了,接下来即使编译和测试了。

四、编译下载验证

4.1 编写 Makefile
新建 Makefile 文件,在 Makefile 文件里面输入如下内容:

示例代码 10.3.2.2 main.c 文件代码
1 objs := start.o main.o
2 
3 ledc.bin:$(objs)
4 arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf $^
5 arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
6 arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
7 
8 %.o:%.s
9 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
10 
11 %.o:%.S
12 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
13 
14 %.o:%.c
15 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
16 
17 clean:
18 rm -rf *.o ledc.bin ledc.elf ledc.dis

第 1 行定义了一个变量 objs,objs 包含着要生成 ledc.bin 所需的材料:start.o 和 main.o,也就是当前工程下的 start.s 和 main.c 这两个文件编译后的.o 文件。这里要注意 start.o 一定要放到最前面!因为在后面链接的时候 start.o 要在最前面,因为 start.o 是最先要执行的文件!

第 3 行就是默认目标,目的是生成最终的可执行文件 ledc.bin,ledc.bin 依赖 start.o 和 main.o如果当前工程没有 start.o 和 main.o 的时候就会找到相应的规则去生成 start.o 和 main.o。比如start.o 是 start.s 文件编译生成的,因此会执行第 8 行的规则。

第 4 行是使用 arm-linux-gnueabihf-ld 进行链接,链接起始地址是 0X87800000,但是这一行用到了自动变量“ ” ,“ ^”,“ ^”的意思是所有依赖文件的集合,在这里就是 objs 这个变量的值:start.o 和 main.o。链接的时候 start.o 要链接到最前面,因为第一行代码就是 start.o 里面的,因此这一行就相当于:
在这里插入图片描述
第 5 行使用 arm-linux-gnueabihf-objcopy 来将 ledc.elf 文件转为 ledc.bin,本行也用到了自动变量“ @ ”,“ @”,“ @”@”的意思是目标集合,在这里就是“ledc.bin”,那么本行就相当于:
在这里插入图片描述
第 6 行使用 arm-linux-gnueabihf-objdump 来反汇编,生成 ledc.dis 文件。

第 8~15 行就是针对不同的文件类型将其编译成对应的.o 文件,其实就是汇编.s(.S)和.c 文件,比如 start.s 就会使用第 8 行的规则来生成对应的 start.o 文件。第 9 行就是具体的命令,这行也用到了自动变量“ @ ”和“ @”和“ @”<”,其中“$<”的意思是依赖目标集合的第一个文件。比如start.s 要编译成 start.o 的话第 8 行和第 9 行就相当于:
在这里插入图片描述
第 17 行就是工程清理规则,通过命令“make clean”就可以清理工程。Makefile 文件就讲到这里,我们可以将整个工程拿到 Ubuntu 下去编译,编译完成以后可以使用软件 imxdownload 将其下载到 SD 卡中,命令如下:
在这里插入图片描述
4.2 链接脚本
在上面的 Makefile 中我们链接代码的时候使用如下语句:
在这里插入图片描述
上面语句中我们是通过“-Ttext”来指定链接地址是 0X87800000 的,这样的话所有的文件都会链接到以 0X87800000 为起始地址的区域。但是有时候我们很多文件需要链接到指定的区域,或者叫做段里面,比如在 Linux 里面初始化函数就会放到 init 段里面。因此我们需要能够自定义一些段,这些段的起始地址我们可以自由指定,同样的我们也可以指定一个文件或者函数应该存放到哪个段里面去。要完成这个功能我们就需要使用到链接脚本,看名字就知道链接脚本主要用于链接的,用于描述文件应该如何被链接在一起形成最终的可执行文件。其主要目的是描述输入文件中的段如何被映射到输出文件中,并且控制输出文件中的内存排布。比如我们编译生成的文件一般都包含 text 段、data段等等。

链接脚本的语法很简单,就是编写一系列的命令,这些命令组成了链接脚本,每个命令是一个带有参数的关键字或者一个对符号的赋值,可以使用分号分隔命令。像文件名之类的字符串可以直接键入,也可以使用通配符“*”。最简单的链接脚本可以只包含一个命令“SECTIONS”,
我们可以在这一个“SECTIONS”里面来描述输出文件的内存布局。我们一般编译出来的代码都包含在 text、data、bss 和 rodata 这四个段内,假设现在的代码要被链接到 0X10000000 这个地址,数据要被链接到 0X30000000 这个地方,下面就是完成此功能的最简单的链接脚本:

示例代码链接脚本演示代码
1 SECTIONS{ 
2 . = 0X10000000; 
3 .text : {*(.text)}
4 . = 0X30000000; 
5 .data ALIGN(4) : { *(.data) } 
6 .bss ALIGN(4) : { *(.bss) } 
7 }

第 1 行我们先写了一个关键字“SECTIONS”,后面跟了一个大括号,这个大括号和第 7 行的大括号是一对,这是必须的。看起来就跟 C 语言里面的函数一样

第 2 行对一个特殊符号“.”进行赋值,“.”在链接脚本里面叫做定位计数器,默认的定位计数器为 0。我们要求代码链接到以 0X10000000 为起始地址的地方,因此这一行给“.”赋值0X10000000,表示以 0X10000000 开始,后面的文件或者段都会以 0X10000000 为起始地址开
始链接。

第 3 行的“.text”是段名,后面的冒号是语法要求,冒号后面的大括号里面可以填上要链接到“.text”这个段里面的所有文件,“(.text)”中的“”是通配符,表示所有输入文件的.text段都放到“.text”中。

第 4 行,我们的要求是数据放到 0X30000000 开始的地方,所以我们需要重新设置定位计数器“.”,将其改为 0X30000000。如果不重新设置的话会怎么样?假设“.text”段大小为 0X10000,那么接下来的.data 段开始地址就是 0X10000000+0X10000=0X10010000,这明显不符合我们的要求。所以我们必须调整定位计数器为 0X30000000。

第 5 行跟第 3 行一样,定义了一个名为“.data”的段,然后所有文件的“.data”段都放到这里面。但是这一行多了一个“ALIGN(4)”,这是什么意思呢?这是用来对“.data”这个段的起始地址做字节对齐的,ALIGN(4)表示 4 字节对齐。也就是说段“.data”的起始地址要能被 4 整除,一般常见的都是 ALIGN(4)或者 ALIGN(8),也就是 4 字节或者 8 字节对齐。

第 6 行定义了一个“.bss”段,所有文件中的“.bss”数据都会被放到这个里面,“.bss”数据就是那些定义了但是没有被初始化的变量。

上面就是链接脚本最基本的语法格式,我们接下来就按照这个基本的语法格式来编写我们本试验的链接脚本,我们本试验的链接脚本要求如下:
①、链接起始地址为 0X87800000。
②、start.o 要被链接到最开始的地方,因为 start.o 里面包含这第一个要执行的命令。
根据要求,在 Makefile 同目录下新建一个名为“imx6ul.lds”的文件,然后在此文件里面输入如下所示代码:

示例代码  imx6ul.lds 链接脚本代码
1 SECTIONS{ 2 . = 0X87800000; 3 .text : 4 { 5 start.o 
6 main.o 
7 *(.text) 8 } 9 .rodata ALIGN(4) : {*(.rodata*)} 
10 .data ALIGN(4) : { *(.data) } 
11 __bss_start = .; 
12 .bss ALIGN(4) : { *(.bss) *(COMMON) } 
13 __bss_end = .;
14 }

第 2 行设置定位计数器为0X87800000,因为我们的链接地址就是0X87800000。第5行设置链接到开始位置的文件为start.o,因为 start.o 里面包含着第一个要执行的指令,所以一定要链接到最开始的地方。第 6 行是 main.o这个文件,其实可以不用写出来,因为 main.o 的位置就无所谓了,可以由编译器自行决定链接位置。在第 11、13 行有“__bss_start”和“__bss_end”这两个东西?这个是什么呢?“__bss_start”和“__bss_end”是符号,第 11、13 这两行其实就是对这两个符号进行赋值,其值为定位符“.”,这两个符号用来保存.bss 段的起始地址和结束地址。前面说了.bss 段是定义了但是没有被初始化的变量,我们需要手动对.bss 段的变量清零的,因此我们需要知道.bss 段的起始和结束地址,这样我们直接对这段内存赋 0 即可完成清零。通过第 11、13 行代码,.bss 段的起始地址和结束地址就保存在了“__bss_start”和“__bss_end”中,我们就可以直接在汇编或者 C 文件里面使用这两个符号。

4.3 修改 Makefile
在上一小节中我们已经编写好了链接脚本文件:imx6ul.lds,我们肯定是要使用这个链接脚本文件的,将 Makefile 中的如下一行代码:
在这里插入图片描述
改为:
在这里插入图片描述
其实就是将-T 后面的 0X87800000 改为 imx6ul.lds,表示使用 imx6ul.lds 这个链接脚本文件。修改完成以后使用新的 Makefile 和链接脚本文件重新编译工程,编译成功以后就可以烧写到 SD 卡中验证了。

4.4 下载验证
使用软件 imxdownload 将编译出来的 ledc.bin 烧写到 SD 卡中,命令如下:
在这里插入图片描述
烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板,如果代码运行正常的话 LED0 就会以 500ms 的时间间隔亮灭。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

X射线源电流电压的实际影响

在进行实际实验的时候&#xff0c;感觉X射线电流电压好像对于成像质量的影响差不多&#xff0c;分不清楚了&#xff0c;这里记录一下&#xff0c;还没探索到原因。 80kv 500uA 功率&#xff1a;40W 90kv 300uA 功率&#xff1a;27W 90kev 600uA 110v 300uA

java的警示之有危险的行为

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;&#x1f468;&#x1f3fb;‍&#x1f393;告别&#xff0c;今天 &#x1f4d4;高质量专栏 &#xff1a;☕java趣味之旅 欢迎&#x1f64f;点赞&#x1f5e3;️评论&#x1f4e5;收藏&#x1f493;关注 &#x1f496;衷心的希…

Sketch webView方式插件开发技术总结

Sketch作为一款广受欢迎的矢量图形设计工具&#xff0c;其功能远不止基础的矢量设计&#xff0c;它的真正实力部分源自其丰富的插件生态系统。Sketch向开发者提供了官方的第三方插件接口&#xff0c;这使得整个社区能够创建和分享众多功能各异的插件&#xff0c;极大地拓展了Sk…

2024最新软件测试【测试理论+ python 编程 】面试题(内附答案)

一、测试理论 3.1 你们原来项目的测试流程是怎么样的? 我们的测试流程主要有三个阶段&#xff1a;需求了解分析、测试准备、测试执行。 1、需求了解分析阶段 我们的 SE 会把需求文档给我们自己先去了解一到两天这样&#xff0c;之后我们会有一个需求澄清会议&#xff0c; …

成熟在用的二级医院手术麻醉系统源码 医疗管理系统源码 自主版权

成熟在用的二级医院手术麻醉系统源码 医疗管理系统源码 自主版权 手术麻醉临床信息系统有着完善的临床业务功能&#xff0c;能够涵盖整个围术期的工作&#xff0c;能够采集、汇总、存储、处理、展现所有的临床诊疗资料。通过该系统的实施&#xff0c;能够规范麻醉科的工作流程…

Spring AOP + 自定义注解 实现公共字段的填充

Spring AOP 自定义注解 实现公共字段的填充 代码冗,不利于后期维护. 定义操作这些字段的方法类型 实现步骤&#xff1a; 自定义注解AutoFill,用于表示操作这些公共字段的方法自定义切面类AutoFillAspect,统一拦截&#xff0c;通过反射获取方法入参&#xff0c;并填充公共字段…

Redis中的复制功能(二)

复制 新版复制功能的实现 为了解决旧版复制功能在处理断线重复制情况时的低效问题&#xff0c;Redis从2.8版本开始&#xff0c;使用PSYNC命令代替SYNC命令来执行复制时的同步操作。 PYSNC命令具有完整重同步(full resynchronization)和部分重同步(partial resynchronization)…

《QT实用小工具·八》数据库通用翻页类

1、概述 源码放在文章末尾 该项目实现数据库通用翻页类&#xff0c;主要包含如下功能&#xff1a; 1:自动按照设定的每页多少行数据分页 2:只需要传入表名/字段集合/每页行数/翻页指示按钮/文字指示标签 3:提供公共静态方法绑定字段数据到下拉框 4:建议条件字段用数字类型的主…

三个AI创业方向各有特点和市场潜力

“AI 客户支持”乃成熟市场——B “AI 社交关系”属新旧交织之领域&#xff1b;——C “AI 企业知识”为专业化且对企业运营至要之领域——B AI 客户支持&#xff08;Al customer support&#xff09;&#xff1a;此方向着重借助 AI 大模型技术&#xff0c;以改良和提升客户服务…

0基础学习Mybatis系列数据库操作框架——多环境配置

大纲 配置代码 在实际开发中&#xff0c;我们往往会将开发环境分成&#xff1a;开发、测试、线上等环境。这些环境的数据源不一样&#xff0c;比如开发环境就不能访问线上环境&#xff0c;否则极容易出现线上数据污染等问题。Mybatis通过多环境配置分开定义来解决这个问题&…

流程控制分支结构

一&#xff0c;流程控制 分为三种&#xff1a;顺序流程控制&#xff0c;分支流程控制&#xff0c;循环流程控制 二&#xff0c;顺序流程控制 先执行A&#xff0c;再执行B 三&#xff0c;分支流程控制if语句 从上到下执行代码的过程中&#xff0c;根据不同的条件&#xff0…

linux操作系统的进程状态

这个博客只是为了自己复习用的&#xff01;&#xff01;&#xff01; 冯诺依曼体系结构 计算机是由一个一个硬件组成的 输入设备&#xff1a;键盘&#xff0c;鼠标&#xff0c;扫描仪&#xff0c;写板等等 中央处理器&#xff08;CPU&#xff09;:含有运算器和控制器等 输出单…

【JavaScript】函数 ④ ( 函数返回值 | 函数返回值语法 return 关键字 | 函数默认返回值 undefined )

文章目录 一、JavaScript 函数返回值1、函数返回值引入2、函数返回值语法3、函数默认返回值4、函数默认返回值 一、JavaScript 函数返回值 1、函数返回值引入 JavaScript 函数 可以 实现某种特定的功能 , 执行完毕后 , 可以返回一个 " 返回值 " ; 当 函数 被调用执行…

结构体内存对齐和位段(重点)!!!

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 点击主页&#xff1a;optimistic_chen和专栏&#xff1a;c语言&#xff0c; 创作不易&#xff0c;大佬们点赞鼓…

【一步一步学】RouterOS Mesh介绍,小白也能懂。

理论介绍 RouterOS Mesh是一种网络拓扑结构&#xff0c;它利用无线技术将多个路由器连接在一起&#xff0c;形成一个覆盖范围更广、信号更稳定的网络。这种结构可以帮助用户实现更好的网络覆盖和负载均衡&#xff0c;提高整体网络性能。 RouterOS Mesh的原理是通过建立多个路由…

C++bitset类型

bitset类型 我们介绍了将整型运算对象当作二进制位集合处理的一些内置运算符。 标准库还定义了bitset类&#xff0c;使得位运算的使用更为容易&#xff0c;并且能够处理超过最长整型类型大小的位集合。bitset类定义在头文件bitset中。 定义和初始化bitset bitset类是一个类模…

【C++庖丁解牛】高阶数据结构---红黑树详解(万字超详细全面介绍红黑树)

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 前言1.红黑树的概念2.红黑…

前端学习<三>CSS进阶——0102-CSS布局样式

前言 css 进阶的主要内容如下。 1、css 非布局样式 html 元素的分类和特性 css 选择器 css 常见属性&#xff08;非布局样式&#xff09; 2、css 布局相关 css 布局属性和组合解析 常见布局方案 三栏布局案例 3、动画和效果 属于 css 中最出彩的内容。 多背景多投影特…

Cookie 和 Session

1. 回顾 Cookie是浏览器在本地持久化存储结构的一种机制. 1.1 Cookie的数据从哪里来? 服务器返回给浏览器的. 1.2 Cookie的数据是什么样的? Cookie的数据是键值对结构. 并且这里的键值对都是程序员自定义的. 1.3 Cookie的作用是什么? Cookie可以在浏览器这边存储一些…

Linux网络编程一(协议、TCP协议、UDP、socket编程、TCP服务器端及客户端)

文章目录 协议1、分层模型结构2、网络应用程序设计模式3、ARP协议4、IP协议5、UDP协议6、TCP协议 Socket编程1、网络套接字(socket)2、网络字节序3、IP地址转换4、一系列函数5、TCP通信流程分析 第二次更新&#xff0c;自己再重新梳理一遍… 协议 协议&#xff1a;指一组规则&…