BIOS启动过程详细解析

1.修改BIOS各步骤的意义

①cpu.h

包含各芯片本身的信息。如core_cm0plus.h, core_cmFunc.h, core_cmInstr.h(KL36)

②mcu.h

为了重定向芯片中的中断信息相关宏常数及宏函数及复位相关函数。

重定向的意义在于

⑴提取共性,最小程度的减少移植其他芯片的代价

⑵为了顾名思义,最大程度提高代码的可读性

③链接文件

主要为了划分各部分功能(动态命令、构件链表、构件函数)所用的区域,实现各个功能的跳转工作。

④启动文件

启动文件的修改主要是将bss段的清零程序删除。删除这段是为了上电复位的时候不清除部分全局变量以达到触碰6次才返回BIOS的效果。

⑤user.h

主要为了重定向各模块的串口、模块号或者对应的原中断处理程序名。

⑥基础构建标准化

主要为了提取共性,实现多芯片的统一。

2.BIOS的启动过程

–> 初始化堆栈

–> 复位程序地址赋给PC寄存器

–> 取出PC寄存器中的地址并执行

–> 将Flash中的data段的数据复制到RAM

–> 调用系统初始化函数进行芯片部分初始化

–> 调用main函数进入BIOS主程序

–> 从BIOS中转向USER区域

mbed操作系统启动过程

(1)芯片上电复位后,芯片内部机制首先从 Flash 的起始地址中,取出第一个表项的内容(即 RAM 最大地址+1),赋给内核堆栈指针寄存器 SP,实际上是使用 MSP,完成堆栈指针初始化。

1
2
3
4
5
.section .FlashConfig, "a"
.long 0xFFFFFFFF
.long 0xFFFFFFFF
.long 0xFFFFFFFF
.long 0xFFFFFFFE

(2)芯片内部机制将第二个表项(即复位处理程序 Reset_Handler 的首地址),赋给内核寄存器 PC(程序计数器)。

(3)芯片内部机制从程序计数器 PC 中取出地址,再从该地址取出机器码,这个机器码就是芯片复位后执行的第一个指令,也就是说,芯片从此开始运行程序了。直观理解就是从“startup_xxx.S”文件中的 Reset_Handler 函数开始程序的运行。

1
2
3
4
5
6
Reset_Handler:
cpsid i
#ifndef __NO_SYSTEM_INIT
bl SystemInit
#endif
cpsie i

(4)将 data 段的数据(已赋值且不为 0 的全局变量和静态变量)从 Flash 中复制到 RAM 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
ldr    r1, =__etext
ldr r2, =__data_start__
ldr r3, =__data_end__

subs r3, r2
ble .LC0

.LC1:
subs r3, 4
ldr r0, [r1,r3]
str r0, [r2,r3]
bgt .LC1
.LC0:

(5)清零未初始化 bss(Block Started by Symbol) 数据段(赋值为 0 或未初始化的全局变量和静态变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define __STARTUP_CLEAR_BSS
#ifdef __STARTUP_CLEAR_BSS
ldr r1, =__bss_start__
ldr r2, =__bss_end__

subs r2, r1
ble .LC3
movs r0, 0

.LC2:
str r0, [r1, r2]
subs r2, 4
bge .LC2

.LC3:
#endif

(6)调用系统初始化函数 SystemInit 进行芯片部分初始化设置(在本样例程序中,完 成系统时钟初始化,即将内核和总线时钟都设置为 48MHZ)。

(7)调用静态构造函数__libc_init_array 完成对 C ++对象的初始化。

(8)最后调用 main 函数进入用户主程序执行。

–> 初始化堆栈

–> 复位程序地址赋给PC寄存器

–> 取出PC寄存器中的地址并执行

–> 将Flash中的data段的数据复制到RAM

–> 清零并初始化BSS段

–> 调用系统初始化函数进行芯片部分初始化

–> (调用__libc_init_array完成对 C ++对象的初始化)

–> 调用main函数进入用户主程序

注意:

1.BIOS的操作中去除了清零并初始化BSS段的操作

2.(__libc_init_array)内为增加操作系统所需要加的操作

NLP的研究内容:

1 . 机器翻译

NLP最早提出的问题就是机器翻译,也就是说,80年代对机器翻译的需求推动了自然语言的蓬勃发展。

2 . 信息检索

存在于我们每天的日常生活中,如百度、谷歌搜索

3 . 自动文摘

如果我们不想看一整篇文章,用这个方法可以获知文章的大概内容,通过观点挖掘获取文章的观点

4 . 问答系统

给计算机一个问题,计算机返回一个答案,不需要我去文档里一个一个找

5 . 信息过滤

过滤没用的信息

6 . 信息抽取

从大量、海量的文章中抽取用户感兴趣的内容

7 . 文档分类

将不同类别的文档分开

8 . 文字编辑和自动校对

9 . 语言教学和文字识别

10 . 语音识别

将人的声音转换为文字

11 . 语音合成

与语音识别相反,给你一段文字,将文字变成声音

12 . 说话人的识别

在很短的时间内快速判断这个说话的人是谁

NLP发展中的基本问题(这些问题限制了NLP的发展)

1 . 形态学问题

秦献公:同德易,同心难,大德大节,求同更难

同德

同德指的是性格和品德相容,同德的两个人关系会更加亲近,但不一定能相交下去。

同心

同心指的是想法和理想接近,同心的两个人才能相交下去,但关系不一定能多好。

历来公室内乱,几曾不是骨肉相残?所谓同德易,同心难。

行—决定了你是一个什么样的人

言—决定了你在别人心中是一个什么样的人

你说的少(该说的说,不该说的别说),做事情又很稳重,别人就会觉得你这个人是值得深交的。在人和人相处的过程中,靠谱, 是很重要的。在那些人心里,会对你有一个印象,谨言慎行的你,在做事情的时候考虑的比别人多一点,说话的时候也能够展现出自己的魅力,那么你的优势已经完全被放大了。

做人要低调,做事要高调

​ 做人要低调,切忌与人无争,无傲气,切记低调,谦虚,不吹嘘,不主动炫耀自己所拥有的资本。

​ 做事要高调,切忌风风火火,切记力求更好,竭尽所能。

无畏,无所谓

​ 切忌做人无畏,做事无所谓。切记做人无所谓,做事无畏。

#JS+HTML+CSS

##第一个Js—鼠标提示框

​ 我们在浏览网页的时候,会出现当鼠标移到某一个选项或者字段的时候会出现提示框,
我们称之为触发事件,以下案例中的鼠标触发事件为鼠标移入事件和鼠标移出事件;
也就是当鼠标移到控件上时会出现一个提示,移出时提示消失。

那我们可以如下这么做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> 无标题文档</title>
</head>

<style>
#div1 {
width:200px;
height:100px;
background: #CCC;
border:1px solid#999;
display: none;}
</style>

<body>
<input type = "checkbox"
onmouseover="document.getElementById('div1').style.display = 'block'"
onmouseout=" document.getElementById('div1').style.display = 'none'"/>

<div id = "div1">
为了您的信息安全。。。。。。
</div>

<input type = "button" value="按钮" onclick="alert('sjdklajdlksj')"/>
</body>
</html>

注意点:

1.document.getElementById(‘div1’).style.display如果直接写出div1.style.display的话就没有兼容性了,部分网页就会失效,所以为了兼容所有网页,写成上面的形式。

2.大家敲HTML语句记得排版,亲测重要性(讲了句废话)

那么这个事件是怎么完成的呢?

首先我们写一个提示框

1
2
3
<div id = "div1">
为了您的信息安全。。。。。。
</div>

并给它设计样式

1
2
3
4
5
6
7
8
<style>
#div1 {
width:200px;
height:100px;
background: #CCC;
border:1px solid#999;
display: none;}
</style>

然后我们需要插入一个类型为checkbox的控件,也就是我们经常看到的多选框,为其添加事件onmouseover,并且添加触发事件后的动作(见代码)。就完成了鼠标提示框的效果。

再看一个例子:

设置一个长高都为200px的红色方框,当鼠标移上去的时候,方框变成长高都为300px的绿色方框,当鼠标移开的时候,再变回来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> 无标题文档</title>
</head>

<style>
#div1 {width:200px;
height:200px;
background: red;}
</style>

<body>

<div id = "div1"
onmouseover=
" document.getElementById('div1').style.width = '300px'
document.getElementById('div1').style.height = '300px'
document.getElementById('div1').style.background = 'green'"
onmouseout=
" document.getElementById('div1').style.width = '200px'
document.getElementById('div1').style.height = '200px'
document.getElementById('div1').style.background = 'red'">
</div>

</body>
</html>

我们发现div内的代码量比较大,当工作量比较大的时候,很明显的不美观、且难以维护。那么我们就需要将这段代码写成一个函数,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> 无标题文档</title>
</head>

<style>
#div1 {
width:200px;
height:200px;
background: red;
}
</style>

<script>
function toGreen()
{
document.getElementById('div1').style.width = '300px'
document.getElementById('div1').style.height = '300px'
document.getElementById('div1').style.background = 'green'
}

function toRed()
{
document.getElementById('div1').style.width = '200px'
document.getElementById('div1').style.height = '200px'
document.getElementById('div1').style.background = 'red'
}
</script>


<body>

<div id = "div1" onmouseover="toGreen()" onmouseout="toRed()">

</div>

</body>
</html>

这样看起来,整个代码看起来就清爽的巴达鸟。

感谢各位的支持!!!!!!!

#C#系列之委托

##什么是委托?

​ 委托,也叫做匿名方法。我们知道,面向对象语言的三大特点其中一个就是封闭性,用户不需要知道函数内部是怎么实现的,只需要调用函数、传入参数就可以直接使用。所以,我们对于一些功能类似,实现方法相同的语句块,我们可以将其作为参数传入。


##为什么要用委托?

首先,我们看一个例子:

写一个返回最大值的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static int Max(List<int> nums)
{
int max = nums[0];
foreach(var num in nums)
{
If(num > max)
max = num;
}
return max;
}

Static void Main(string[] args)
{
Console.WriteLine(Max(new List<int>(){1,2,3,4,5}));//输出最大值
Console.ReadLine();//暂停,让程序结果能让使用者看到

}

​ 那怎么写一个返回最小值的方法呢,我们只需要把num > max 这个判断条件改为num < max(max只是个名字而已,不用纠结含义),但每次去修改函数就破坏了封装性,那么我们最开始想到的方法就是枚举。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
enum 返回值
{
max,
min,
}
static int Max(List<int> nums,返回值 retType)
{
int max = nums[0];
foreach(var num in nums)
{
switch(retType)
{
case 返回值.max:
if(num >max)
max = num;
break;
case 返回值.min:
if(num <max)
max = num;
break;
}
}
return max;
}
Static void Main(string[] args)
{
Console.WriteLine(Max(new List<int>(){1,2,3,4,5},返回值.min));
Console.ReadLine();//暂停,让程序结果能让使用者看到
}

​ 但这种方法还是有问题,如果我们要增加平均值函数,我们就又需要修改函数中的代码。
​ 我们知道面向对象编程其中一个特点就是封闭性,而我们每次新增功能都需要修改函数中的代码,这样就破坏了函数的封闭性。

再看一个例子

比如,遍历List,挑选出>=10的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
static  List<int> Traverse(List<int> nums)
{
Var list = new List<int>();

foreach(var num int nums)
{
If(num >= 10)
{
List.Add(num);
}
}
return list;
}

如果增加一个功能,遍历一下偶数
那就是把num >= 10 改为 num % 2 == 0

num >= 10 和 num % 2 == 0有什么共同点?
1.两者返回值都是bool值
2.两者只需要传入一个参数num

那么我们可以尝试把这个函数写成function(num)
static bool function(int num)
{
return num >= 10;
}
但是这种方法依旧没有封装住,为什么?
因为这个函数不是作为函数参数传入进来,而是作为函数调用传入进来,这样每次功能需求变化的时候,我们每次都要修改function里面的内容,或者另外写function2(num),无论哪种方法都无法封装住,那么我们每次需要增加新功能时都需要修改代码,当代码工程量比较大时,代码维护工作量很大。那么我们是不是可以用一个匿名函数(也就是每次不需要修改名字),就可以避免修改函数中的代码来达到封装的效果呢?那么,委托就可以如此。


##委托要怎么做呢?

委托需要以下三步:
声明委托类型:delegate bool Function(int num);
修改形参列表:static List Traverse(List nums,Function function)
传入委托:var list = Traverse(new List() {1,2,3,4,5,6,7}, GreaterThan10);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
delegate bool Function(int num);//声明委托类型
static Function GreaterThan10 = delegate(int num) { return num >= 10;};
static Function IsEven = delegate(int num) { return num >= 10;};

static List<int> Traverse(List<int> nums,Function function)//修改形参列表
{
Var list = new List<int>();
foreach(var num int nums)
{
If(function(num))
{
List.Add(num);
}
}
return list;
}

Static void Main(string[] args)
{
var list = Traverse(new List<int>() {1,2,3,4,5,6,7}, GreaterThan10);//传入委托
Console.WriteLine(Max(new List<int>(){1,2,3,4,5},返回值.min));
Console.ReadLine();//暂停,让程序结果能让使用者看到
}

##Lambda是对委托的化简写法

###语句Lambda
(type var,…) =>{ … }
(var, …) => { … }
Var => { … }
() => { … }

###表达式Lambda
没有{},但是只能有一条语句

既然GreaterThan10 = delegate(int num) { return num >= 10;}
那我们直接可以把
var list = Traverse(new List() {1,2,3,4,5,6,7}, GreaterThan10)写成:
var list = Traverse(new List() {1,2,3,4,5,6,7}, delegate(int num) { return num >= 10;});

继续化简
var list = Traverse(new List() {1,2,3,4,5,6,7}, (int num) => { return num >= 10;});
再继续化简
既然申明delegate bool Function(int num)时已经声明num为int类型,那我们为什么还要再写int num?
var list = Traverse(new List() {1,2,3,4,5,6,7},(num) => { return num >= 10;});
当需要且仅需要一个参数时,我们连括号都可以省了
var list = Traverse(new List() {1,2,3,4,5,6,7}, num => { return num >= 10;});
当只有一个参数,一条语句时
var list = Traverse(new List() {1,2,3,4,5,6,7}, num => return num >= 10);
当没有参数时
var list = Traverse(new List() {1,2,3,4,5,6,7}, () => { return num >= 10;});


##系统自带的泛型委托

Action 例 List.ForEach()
Func 例 List.Sum()
Predicate 例 List.FindAll()
例 List.Find()

###Action泛型委托

Action是无返回值的委托

Action action = delegate void xx();
public delegate void Action(T1 t);
list.ForEach(i =>Console.WriteLine(i));
list.ForEach(i =>{Console.WriteLine(i)});

###Func泛型委托

Func是有返回值的委托
list.Sum(n => {if(n <= 0) return 0; else return n)}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static Func<int,bool> GreaterThan10 = delegate(int num) { return num >= 10;}; 
static Func<int,bool> IsEven = delegate(int num) { return num >= 10;};

static List<int> Traverse(List<int> nums,Func<int,bool> function)
{
Var list = new List<int>();
foreach(var num int nums)
{
If(function(num))
{
List.Add(num);
}
}
return list;
}

###Predicate 谓词—返回bool值的委托

list.FindAll(n => n < 0);

#程序安装

##第一步-下载开发工具
首先,我们可以尝试去Arduino官网下载区下载开发工具,但遗憾的是,官网的软件速度较慢。这里给大家另外放上一个下载地址,耐心等待一会。

##第二步-安装开发工具

开发工具下载完成后,开始安装开发工具,安装过程不需要多余操作,默认安装到底。

##第三步-检查是否有串口信息

一般情况下,开发工具下载完会安装驱动CH340,而非正版软件有可能并没有驱动,此时我们需要去下载CH340驱动,下载完成后去设备管理器检查是否有设备信息。

谢谢大家的观看