snprintf
// char *p = "hello";
// char *p2 = "world";
char buf[15];
int n = snprintf(buf, sizeof(buf), "%s%s%d", "hello", "world", 123);
printf("n = %d, buf = %s\n", n, buf);
/* n = 13, buf = helloworld123 */
typedef
在C99标准中定义了这些数据类型,具体定义在stdint.h
中
【C语言】uint8_t、uint16_t、uint32_t、uint64_t是什么?_雪 风的博客-优快云博客
/* exact-width signed integer types */
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed __INT64 int64_t;
/* exact-width unsigned integer types */
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned __INT64 uint64_t;
串口中断接收完成判断的方法
- 在接收数据时启动一个定时器,在指定时间间隔内没有接收到新数据,认为数据接收完成。
- 在数据中加入帧头、帧尾,通过在程序中判断是否接收到帧尾来确定数据接收完毕。
- 使用空闲帧中断,用户可以通过获取该中断标志位来判断数据是否接收完成。
字符数组和字符串有什么区别?
在c语言中,并不存在字符串这个数据类型,而是使用字符数组来保存字符串,但是字符数组和字符串是完全不相同的两个概念。
#include<stdio.h>
#include<string.h>
int main()
{
//字符数组
char arr[] = {'H','E','L','L','O'};
//字符串
char str[] = "HELLO";
printf("sizeof(arr) = %ld\n", sizeof(arr));
printf("sizeof(str) = %ld\n", sizeof(str));
printf("strlen(arr) = %ld\n", strlen(arr));
printf("strlen(str) = %ld\n", strlen(str));
printf("arr = %s\n", arr);
printf("str = %s\n", str);
}
/*
sizeof(arr) = 5
sizeof(str) = 6
strlen(arr) = 10
strlen(str) = 5
arr = HELLOHELLO
str = HELLO
*/
字符数组:H E L L O 未知内容。对于字符数组则不会自动增加任何的内容。
字符串:H E L L O \0。对于字符串,c语言在编译的时候会自动在末尾加一个null字符,也就是'\0',用16进制表示就是0x00。
计算字符数组的长度,sizeof(arr) = 5。
计算字符串的长度,sizeof(str) = 6,之所以为6,是因为str是一个字符串,编译的时候在后面增加一个null字符。
为什么strlen(arr) = 10?实际上strlen会一直计算字符数组的长度,直到遇到'\0',在定义arr的时候,在内容里面开辟5个char大小的空间给arr使用,但这内容之后,到底是不是'\0',我们不得而知,所以strlen(arr)的值有可能大于5。
字符串str末尾肯定有'\0',所以strlen(str) = 5。
使用printf打印arr的时候,有时候会发现在O之后会出现意想不到的字符,而打印str完全正常。
数组指针
#include <stdio.h>
int main()
{
int arr[3][4] = {{11,22,33,44},{12,13,15,16},{22,66,77,88}};//arr++
int i,j;
//能不能定义一个指针,让指针偏移的时候,也偏移对应大小的数组?
//数组指针,定义一个指针,指向一个数组!
//数组指针才是真正等同于二维数组名
int (*p2)[4];
p2 = arr;
// printf("p2=%p\n",p2);
// printf("++p2=%p\n",++p2);
for(i=0;i<3;i++){
for(j=0;j<4;j++){
//printf("%d\n",*(*(arr+i)+j));
printf("%d\n",*(*(p2+i)+j));
}
}
}
/*
11 22 33 44 12 13 15 16 22 66 77 88
*/
#if 0
//以前写法,这样写有点失去二维数组的味道
#include <stdio.h>
//arr,arr[0]
int main()
{
int arr[3][4] = {{11,22,33,44},{12,13,15,16},{22,66,77,88}};//arr++
int i,j;
int *p;//p++
p = &arr[0][0];
// p = arr; //warning: assignment from incompatible pointer type 来自不兼容指针类型的赋值
//assignment to 'int *' from incompatible pointer type 'int (*)[4]' 从不兼容的指针类型“int(*)[4]”分配到“int*”
for(i=0;i<12;i++){
printf("%d\n",*p++);//导致p++会有风险
}
}
#endif
数组指针和二维数组的应用
#include <stdio.h>
int getTheData(int (*p)[4],int hang,int lie)
{
int data;
data = *(*(p+hang)+lie);
return data;
//return p[hang][lie];
}
void tipsInputHangLie(int *pm, int *pn)
{
printf("输入行列值:\n");
scanf("%d%d",pm,pn);
puts("done!");
}
//arr,arr[0]
int main()
{
int arr[3][4] = {{11,22,33,44},{12,13,15,16},{22,66,77,88}};//arr++
int ihang,ilie;
int data;
//1. 提示用户输入行列值
tipsInputHangLie(&ihang,&ilie);
//2. 找出对应行列值的那个数
data = getTheData(arr,ihang,ilie);
//3. 打印出来
printf("%d行%d列的值是%d\n",ihang,ilie,data);
}
/*
输入行列值:
0
0
done!
0行0列的值是11
*/
函数指针
#include <stdio.h>
void printWelcome()
{
puts("程序启动,欢迎使用\n");
}
int main()
{
int a = 10;
int *pa;
pa = &a;
printf("%d\n",*pa);
void (*p)();//定义一个函数指针变量
p = printWelcome;//指向函数
//printWelcome();
//(*p)();//调用1 //直接通过指针名字 + ()
(p)();//调用2 //取函数内容(*指针名字)()
return 0;
}
/*
10
程序启动,欢迎使用
*/
函数指针2
#include <stdio.h>
int inCData(int data)
{
return ++data;
}
void printWelcome()
{
puts("程序启动,欢迎使用\n");
}
int main()
{
void (*p)();//定义一个函数指针变量
int (*p2)(int data);
p = printWelcome;//指向函数
p2 = inCData;
(*p)();//调用
printf("p2测试:%d\n",(*p2)(10));
return 0;
}
/*
程序启动,欢迎使用
p2测试:11
*/
函数指针3
#include <stdio.h>
#include <stdlib.h>
int getMax(int data1, int data2)
{
return data1>data2 ? data1:data2;
}
int getMin(int data1, int data2)
{
return data1<data2 ? data1:data2;
}
int getSum(int data1, int data2)
{
return data1+data2;
}
/*
int dataHandler(int data1, int data2, int (*pfunc)(int, int )) //lyf强调形参是什么类型的数据,参数名只是一个访问方式
{
int ret;
ret = (*pfunc)(data1,data2);
return ret;
}
*/
int main()
{
int a = 10;
int b = 20;
int cmd;
int ret;
int (*pfunc)(int , int ); //lyf强调形参是什么类型的数据,参数名只是一个访问方式
printf("请输入1(取大值),2(取小值),或者3(求和)\n");
scanf("%d",&cmd);
switch(cmd){
case 1:
pfunc = getMax;
break;
case 2:
pfunc = getMin;
break;
case 3:
pfunc = getSum;
break;
default:
printf("输入错误!@输入1(取大值),2(取小值),或者3(求和)\n");
// exit(-1);
break;
}
/*
ret = dataHandler(a,b,pfunc);//50行不加exit(-1),用gdb调试有段错误,因为switch输入错误的话,pfunc是个野指针 lyf
printf("ret = %d\n",ret);
*/
printf("ret = %d\n",pfunc(a,b));//lyf等价于19-24 51-52
return 0;
}
/*
请输入1(取大值),2(取小值),或者3(求和)
1
ret = 20
rlk@rlk:Downloads$ ./a.out
请输入1(取大值),2(取小值),或者3(求和)
2
ret = 10
rlk@rlk:Downloads$ ./a.out
请输入1(取大值),2(取小值),或者3(求和)
3
ret = 30
*/
指针数组
一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都存放一个地址,相当于一个指针变量。
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
int d = 40;
int* p[4] = {&a,&b,&c,&d};
int i;
for(i = 0;i<4;i++){
printf("%d ",*(p[i]));//*p[i] 中括号的优先级高于*,但是在工作中还是希望加上() lyf
}
return 0;
}
/*
10 20 30 40
*/
函数指针数组
#include <stdio.h>
#include <stdlib.h>
int getMax(int data1, int data2)
{
return data1>data2 ? data1:data2;
}
int getMin(int data1, int data2)
{
return data1<data2 ? data1:data2;
}
int getSum(int data1, int data2)
{
return data1+data2;
}
int main()
{
int a = 10;
int b = 20;
int ret;
int (*pfunc[3])(int , int )={
getMin,
getMax,
getSum};//函数指针数组!
int i;
for(i=0;i<3;i++){
ret = (*pfunc[i])(a,b);
printf("ret = %d\n",ret);
}
return 0;
}
/*
ret = 10
ret = 20
ret = 30
*/
指针函数
返回指针的函数
#include <stdio.h>
int* getPosPerson(int pos, int (*pstu)[4])//指针函数,返回指针的函数
//数组指针 指向一个含有4个元素的数组
{
int *p;
p = (int *)(pstu+pos);//lyf pstu(父数组)+pos偏移整个数组,相当于arr+1,就是第二行的全部元素
return p; //类型不一致,因为pstu++偏移了16个字节,p++偏移了4个字节,但是没关系,我们拿回来了p的地址
} //int *p; char *c; 指针操作关心两个问题:1.起始位置 2.偏移值,这段代码只关心起始位置,不关心偏移值
//消除警告,就是在前面加(int *)类型强转
int main()
{
int scores[3][4]={
{55,66,77,88},
{66,55,99,100},
{11,22,33,59},
};
int *ppos;
int pos;
printf("请输入你需要看的学生号数:0,1,2\n");
scanf("%d",&pos);
ppos = getPosPerson(pos, scores);
int i;
for(i=0;i<4;i++){
printf("%d ",*ppos++);
}
return 0;
}
/*
J:\lyf\03.other\2023.7.3\code-new\第六章指针>a.exe
请输入你需要看的学生号数:0,1,2
0
55 66 77 88
J:\lyf\03.other\2023.7.3\code-new\第六章指针>a.exe
请输入你需要看的学生号数:0,1,2
1
66 55 99 100
J:\lyf\03.other\2023.7.3\code-new\第六章指针>a.exe
请输入你需要看的学生号数:0,1,2
2
11 22 33 59
*/
二级指针
#include <stdio.h>
int main()
{
int data = 100;
int *p = &data;
printf("data的地址是:%p\n",&data);
printf("p保存data的地址:%p,内容是%d\n",p,*p);
/* 可以用一级指针变量存放指针变量的地址,但是使用有缺陷,无法获得最终地址内容 */
// printf("p的地址是:%p\n",&p);
// int *pp = &p;
// printf("pp保存p的地址:%p\n",pp);
// printf("*pp是%p\n",*pp);
int **p2;
p2 = &p;
printf("p2保存p的地址:%p\n",p2);
printf("*p2是%p\n",*p2);
printf("**p2来访问data:%d\n",**p2);
int ***p3;
p3 = &p2;
printf("p3保存p2的地址:%p\n",p3);
printf("*p3是%p2\n",*p3);
printf("***p3来访问data:%d\n",***p3);
return 0;
}
/*
data的地址是:000000000061FE0C
p保存data的地址:000000000061FE0C,内容是100
p的地址是:000000000061FE00
pp保存p的地址:000000000061FE00
*pp是000000000061FE0C
p2保存p的地址:000000000061FE00
*p2是000000000061FE0C
**p2来访问data:100
p3保存p2的地址:000000000061FDF8
*p3是000000000061FE002
***p3来访问data:100
*/
二级指针的应用
//这个是二级指针的用法
#include <stdio.h>
// void getPosPerson(int pos, int (*pstu)[4], int *ppos)//函数指针,返回指针的函数 xx
void getPosPerson(int pos, int (*pstu)[4], int **ppos)//函数指针,返回指针的函数 xx
{
*ppos = (int *)(pstu+pos);
}
int main()
{
int scores[3][4]={
{55,66,77,88},
{66,55,99,100},
{11,22,33,59},
};
int *ppos;
int pos;
printf("请输入你需要看的学生号数:0,1,2\n");
scanf("%d",&pos);
//getPosPerson(pos, scores, ppos); //如果第4行、第22行对应使用的话,第17行ppos是野指针,没有初始化,第25行继续打印的话,会出现段错误,正确的处理是23行和第5行配合使用
getPosPerson(pos, scores, &ppos);
for(int i=0;i<4;i++){
printf("%d ",*ppos++);
}
return 0;
}
/*
J:\lyf\03.other\2023.7.3\code-new\第六章指针>a.exe
请输入你需要看的学生号数:0,1,2
0
55 66 77 88
J:\lyf\03.other\2023.7.3\code-new\第六章指针>a.exe
请输入你需要看的学生号数:0,1,2
1
66 55 99 100
J:\lyf\03.other\2023.7.3\code-new\第六章指针>a.exe
请输入你需要看的学生号数:0,1,2
2
11 22 33 59
*/
/*
#include <stdio.h>
void getPosPerson(int pos, int (*pstu)[4],int *ppos)//函数指针,返回指针的函数 xx
{
ppos = (int *)(pstu+pos);
int i;
for(i=0;i<4;i++){
printf("%d ",*ppos++);
}
}
int main()
{
int scores[3][4]={
{55,66,77,88},
{66,55,99,100},
{11,22,33,59},
};
int *ppos;
int pos;
printf("请输入你需要看的学生号数:0,1,2\n");
scanf("%d",&pos);
getPosPerson(pos, scores,ppos);
int i;
for(i=0;i<4;i++){
printf("%d ",*ppos++);
}
return 0;
}*/
二级指针的认识
//是二级指针的认识,一般不会这么用
#include <stdio.h>
int main()
{
int scores[3][4]={
{55,66,77,88},
{66,55,99,100},
{11,22,33,59},
};//int (*p)[4];
/*
int **p;
p = scores; //会出问题!
printf("scores:%p\n",scores);
printf("p=%p\n",p);
printf("*p=%p\n",*p);//*p是一个野指针,不是我们认为的会变成列地址
printf("*score=%p\n",*scores);
**p = 100; //对野指针发起访问,就会发生段错误,第22行代码不会执行
printf("done\n");
// scores:000000000061FDE0
// p=000000000061FDE0
// *p=0000004200000037
// *score=000000000061FDE0
//第20行发生了段错误,运行起来光标在转圈圈,退出
*/
int (*p2)[4] = scores;
int **p3 = &p2;//能用
**p3 = 100;//能改的动,但是一般不这么进行
printf("%d\n",scores[0][0]);
//100
return 0;
}
各种指针的定义
1. 一个整形数:int a;
2. 一个指向整形数的指针:int *a;
3. 一个指向指针的指针,它指向的指针指向一个整型数:int **a;
4. 一个有10个整型数的数组:int a[10];
5. 一个有10个指针的数组,每个指针指向一个整型数:int *a[10];
6. 一个指向有10个整型数的数组的指针:int (*a)[10];
7. 一个指向指针的指针,被指向的指针指向一个有10个整型数的数组:int (**a)[10];
8. 一个指向数组的指针,该数组有10个整形指针:int *(*a)[10];
9. 一个指向函数的指针,该函数有一个整形参数并返回一个整形数:int (*a)[10];
10. 一个有10个指针的数组,每个指针指向一个函数,该函数有一个整形参数并放回一个整型数:int (*a[10])(int);
11. 一个函数的指针,指向的函数类型是有两个整形参数并且返回一个函数指针的函数,返回的函数指针指向有一个整形参数且返回整形数的函数:int(*(*a)(int, int))(int);
栈区
不要返回局部变量的地址,因为局部变量在函数执行之后就释放了,我们没有权限取操作释放后的内存
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//栈 注意事项 ,不要返回局部变量的地址
int * func()
{
int a = 10;
return &a;
}
void test01()
{
int * p = func();
//结果已经不重要了,因为a的内存已经被释放了,我们没有权限去操作这块内存
printf("a = %d\n", *p);
printf("a = %d\n", *p);
}
char * getString()
{
char str[] = "hello world";
return str;
}
void test02()
{
char * p = NULL;
p = getString();
printf("%s\n", p);
}
int main(){
//test01();
test02();
system("pause");
return EXIT_SUCCESS;
}
这样写是正确的
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int * func()
{
int b = 10;
int *a = &b;
return a;
}
void test01()
{
int * p = func();
printf("a = %d\n", *p);
printf("a = %d\n", *p);
}
/*
a = 10
a = 10
*/
void getString(char *p)
{
strcpy(p, "hello");
}
void test02()
{
//分配到栈上
char buf[128] = {0};
getString(buf);
printf("%s\n", buf);
}
int main(){
test01();
// test02();
// system("pause");
return 0;
}
堆区
在堆区开辟的数据,记得手动开辟,手动释放
注意事项:如果在主调函数中没有给指针分配内存,那么被调函数中需要利用高级指针给主调函数中指针分配内存
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int * getSpace()
{
int * p = malloc(sizeof(int)* 5);
if (p == NULL)
{
return NULL;
}
for (int i = 0; i < 5;i++)
{
p[i] = i + 100;
}
return p;
}
void test01()
{
int * p = getSpace();
for (int i = 0; i < 5;i++)
{
printf("%d ", p[i]);
}
//手动在堆区创建的数据,记得手动释放
free(p);
p = NULL;
}
/*
100 101 102 103 104
*/
//注意事项
//如果主调函数中没有给指针分配内存,被调函数用同级指针是修饰不到主调函数中的指针的
void allocateSpace( char * pp )
{
char * temp = malloc(100);
if (temp == NULL)
{
return;
}
memset(temp, 0, 100);
strcpy(temp, "hello world");
pp = temp;
}
void test02()
{
char * p = NULL;
allocateSpace(p);
printf("%s\n", p);
}
/*
Segmentation fault (core dumped)
*/
void allocateSpace2(char ** pp)
{
char * temp = malloc(100);
memset(temp, 0, 100);
strcpy(temp, "hello world");
*pp = temp;
}
void test03()
{
char * p = NULL;
allocateSpace2(&p);
printf("%s\n", p);
free(p);
p = NULL;
}
/*
hello world
*/
int main(){
//test01();
//test02();
test03();
system("pause");
return EXIT_SUCCESS;
}
栈的生长方向及内存存储方式
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//1、栈的生长方向
void test01()
{
int a = 10; //栈底 --- 高地址
int b = 20;
int c = 30;
int d = 40; //栈顶 --- 低地址
printf("a的地址:%p\n", &a);
printf("b的地址:%p\n", &b);
printf("c的地址:%p\n", &c);
printf("d的地址:%p\n", &d);
}
/*
a的地址:0x7ffe8e682438
b的地址:0x7ffe8e68243c
c的地址:0x7ffe8e682440
d的地址:0x7ffe8e682444
*/
//2、内存存储方式
void test02()
{
int a = 0xaabbccdd;
unsigned char * p = &a;
printf("0x%x\n", *p); // 低位字节数据 ---- 低地址
printf("0x%x\n", *(p+1)); // 高位字节数据 ---- 高地址
printf("0x%x\n", *(p + 2));
printf("0x%x\n", *(p + 3));
}
/*
0xdd
0xcc
0xbb
0xaa
*/
int main(){
// test01();
test02();
// system("pause");
return EXIT_SUCCESS;
}
指针做函数参数的输入输出特性
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//1、输入特性: 主调函数中分配内存,被调函数中使用内存
void func(char * p)
{
strcpy(p, "hello world");
}
void test01()
{
//分配到栈上
char buf[1024] = { 0 };
func(buf);
printf("%s\n", buf);
}
void printString(char * str)
{
printf("%s\n", str);
}
void test02()
{
//分配到堆区
char * p = malloc(sizeof(char)* 64);
memset(p, 0, 64);
strcpy(p, "helloworld");
printString(p);
free(p);
p = NULL;
}
//2、输出特性: 被调函数分配内存,主调函数使用内存
void allocateSpace(char ** pp)
{
char * temp = malloc(sizeof(char)* 64);
memset(temp, 0, 64);
strcpy(temp, "hello world");
*pp = temp;
}
void test03()
{
char * p = NULL;
allocateSpace(&p);
printf("%s\n", p);
//手动在堆区创建的数据,记得手动释放
free(p);
p = NULL;
}
int main(){
//test01();
//test02();
test03();
system("pause");
return EXIT_SUCCESS;
}
总结
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void func(char *p)
{
strcpy(p, "hello");
}
void test01()
{
//分配到栈区
char buf[128] = {0};
func(buf);
printf("%s\n", buf);
}
/*hello*/
/*==========================================*/
void printfString(char *str)
{
printf("%s\n", str);
}
void test02()
{
//分配到堆区
char *p = malloc(sizeof(char) * 128);
memset(p, 0, 128);
strcpy(p, "hello world");
printfString(p);
free(p);
p = NULL;
}
/*hello world*/
/*==========================================*/
void function(char **pp)
{
//分配到堆区
char *temp = malloc(sizeof(char) * 128);
memset(temp, 0, 128);
strcpy(temp, "123456");
*pp = temp;
}
void test03()
{
char *p = NULL;
function(&p);
printf("%s\n", p);
free(p);
p = NULL;
}
/*123456*/
/*==========================================*/
char *function1()
{
//分配到堆区
char *p = malloc(sizeof(char) * 128);
memset(p, 0, 128);
strcpy(p, "nihao");
return p;
}
void test04()
{
char *p = function1();
printf("%s\n", p);
free(p);
p = NULL;
}
/*nihao*/
int main(){
// test01();
// test02();
// test03();
test04();
// system("pause");
return EXIT_SUCCESS;
}
1. keil的安装
FreeRTOS完全开发手册之上册_快速入门.pdf
2. STM32·FreeRTOS·新建工程模板
3. freeRTOS源码结构与编程规范
FreeRTOS完全开发手册之上册_快速入门.pdf
4.使用STM32CubeMX创建RTOS工程模板
E:\git\rtos_doc_source\RTOS培训资料\02_项目2_基于FreeRTOS实现智能家居\02_CubeMX对FreeRTOS的适配\2_学习文档\00_FreeRTOS工程模板建立.md
该工程是在“5_4_Serialport_RingBuffer_GPIO_IRQ
”工程基础上创建一个带有RTOS的工程模板,使用的工具是STM32CubeMX
5.02_STM32CubeMX生成Makefile工程及其编译环境搭建
E:\git\rtos_doc_source\RTOS培训资料\03_项目3_深入理解ARM架构实现多任务系统\2_学习文档\02_STM32CubeMX生成Makefile工程及其编译环境搭建.md
1.目的;2.环境:2.1.windows下安装arm-gcc、2.2.windows下安装马克命令环境;3.STM32CubeMX生成GCC工程;4.使用Git编译;5.使用STM32CubeProgrammer 烧录;6.修改Makefile添加代码。
6.GPIO寄存器操作
E:\git\doc_and_source_for_mcu_mpu\STM32MF103\doc_pic\03_第1个程序(点灯)\02_GPIO引脚操作方法概述.docx
GPIO寄存器的2种操作方法:
原则:不能影响到其他位,直接读写:读出、修改对应位、写入
要设置bit n:
val = data_reg;
val = val | (1<<n);
data_reg = val;
要清除bit n:
val = data_reg;
val = val & ~(1<<n);
data_reg = val;
5.软件定时器消除抖动
E:\git\rtos_doc_source\RTOS培训资料\02_项目2_基于FreeRTOS实现智能家居\01_FreeRTOS快速入门\1_项目源码\02_视频配套的源码
26_freertos_example_readkey
6.单片机主频和定时器的关系
在传统51单片机中,一个机器周期=12个时钟周期,这意味着单片机的时钟频率越高,其机器周期就越短,从而使得定时器的计时精度提高。例如,如果一个单片机使用12MHz的晶振,那么一个机器周期就是1微秒(us),这意味着定时器可以以微秒为单位进行精确计时。
时钟周期:也叫振荡周期或晶振周期,即晶振的单位时间发出的脉冲数,一般有外部的振晶产生,比如12MHZ=12×10的6次方,即每秒发出12000000个脉冲信号,那么发出一个脉冲的时间就是时钟周期,也就是1/12微秒。通常也叫做系统时钟周期。是计算机中最基本的、最小的时间单位。
机器周期:在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段,每一阶段完成一项工作。例如,取指令、存储器读、存储器写等,这每一项工作称为一个基本操作。完成一个基本操作所需要的时间,称为机器周期。
指令周期:指令周期是执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期数也不同。对于一些简单的的单字节指令,在取指令周期中,指令取出到指令寄存器后,立即译码执行,不再需要其它的机器周期。对于一些比较复杂的指令,例如转移指令、乘法指令,则需要两个或者两个以上的机器周期。
系统时钟:系统时钟就是CPU指令运行的频率,这个才是CPU真正的频率。
bin文件扩大为0x2000,
bin文件不保存初始值为0,或者没有初始值的变量。