单片机

单片机(Microcontroller, MCU)是一种集成了计算机功能的微型计算机,通常由一个微处理器(CPU)、存储器(ROM、RAM)、输入/输出接口、定时器/计数器等功能模块集成在同一芯片上。单片机是一种常用于嵌入式系统中的控制器,它被广泛应用于家电、汽车、工业自动化、医疗设备、消费电子、物联网(IoT)设备等多个领域。

计算机处理器以晶体管集成电路技术的发展而在不断前进。早期的处理器是通过二极管搭建的逻辑计算器。随着现代加工业的发展,处理器使用集成电路构建。现代计算机处理器是在一片单晶硅上,通过刻腐机雕刻并制作各种晶体管电路,实现高度集成的计算功能的电路集合体。

计算机根据功能特性主要有:中央处理器(简称CPU)、专用数字处理器(DSP)可编程门阵列(简称FPGA)、片上系统(简称SOC)、微处理器(简称MCU)等。为此作如下分析:

(1)CPU类处理器主要应用在个人电脑上,它是电脑上“枢纽中心”,主要功能是实现其他电路的沟通桥梁作用。现代CPU内部集成度较高,一般含有传感器、图形加速器、内存管理器、少量必要的随机存取存储器(简称RAM)和只读存储器(简称ROM)。CPU具有高速运算能力和处理能力,支持操作系统的移植,便于大型平台的开发。但它的价格偏高、指令复杂,故在本系统中不适宜采用。

(2)DSP类处理器主要应用在需要复杂计算处理的场景。DSP内部集成专用浮点数计算,支持高速傅里叶转换,可以高速实现复杂数据计算。最常见的应用为电脑的“显卡”。除此之外,在工业领域中具有较高的应用范围,如电源类。该处理具备RAM和ROM,支持多种外设接口。该类处理器一般用于复杂运算系统上,故在本系统中不适宜采用。

(3)SOC类处理器又叫“片上系统”,它包括基本的CPU运算处理器、RAM和ROM类的存储器。SOC由于具有良好的外设功能,减少了设计周期和成本。现代的SOC支持精简指令,支持操作系统移植,便于大型平台的开发。SOC的价格仍然偏高,故在本系统中不适宜采用。

(4)MCU微处理器和SOC功能较为相似,属于精简版的SOC,且具有独立运算功能,和支持外设。MCU有点:性价比相对特别高,指令简单,适用做小型系统的核心控制器。MCU缺点:运算处理能力差,在设计要求稳定高速的浮点数条件下,基本无法实现要求,但是在小型系统设计来说,其作为控制芯片最为合适。

MCU一般被称作“单片机”,它的体积很小,可以安装在任何小型仪器或者设备当中。它是把CPU、RAM、ROM、输入/输出端口(I/0)等主要计算机功能部件都集成在一块集成电路芯片上的微型计算机。MCU的发展给小型化电子设备发展带来可能。

版权声明:本文为CSDN博主「武力戡乱」的原创文章,
遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
https://blog.csdn.net/st441747863/article/details/104792415

围观 73

一、五大内存分区

内存分成5个区,它们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

1、栈区(stack):FIFO就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。

2、堆区(heap):就是那些由new分配的内存块,它们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

3、自由存储区:就是那些由malloc等分配的内存块,它和堆是十分相似的,不过它是用free来结束自己的生命。

4、全局/静态存储区:全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

5、常量存储区:这是一块比较特殊的存储区,它们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)

code/data/stack

内存主要分为代码段,数据段和堆栈。代码段放程序代码,属于只读内存。数据段存放全局变量,静态变量,常量等,堆里存放自己malloc或new出来的变量,其他变量就存放在栈里,堆栈之间空间是有浮动的。数据段的内存会到程序执行完才释放。调用函数先找到函数的入口地址,然后计算给函数的形参和临时变量在栈里分配空间,拷贝实参的副本传给形参,然后进行压栈操作,函数执行完再进行弹栈操作。字符常量一般放在数据段,而且相同的字符常量只会存一份。

二、C语言程序的存储区域

1、由C语言代码(文本文件)形成可执行程序(二进制文件),需要经过编译-汇编-连接三个阶段。编译过程把C语言文本文件生成汇编程序,汇编过程把汇编程序形成二进制机器代码,连接过程则将各个源文件生成的二进制机器代码文件组合成一个文件。

2、C语言编写的程序经过编译-连接后,将形成一个统一文件,它由几个部分组成。在程序运行时又会产生其他几个部分,各个部分代表了不同的存储区域:

1)代码段(Code或Text)

代码段由程序中执行的机器代码组成。在C语言中,程序语句执行编译后,形成机器代码。在执行程序的过程中,CPU的程序计数器指向代码段的每一条机器代码,并由处理器依次运行。

2)只读数据段(RO data)

只读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。

3)已初始化读写数据段(RW data)

已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并且有初值,以供程序运行时读写。

4)未初始化数据段(BBS)

未初始化数据是在程序中声明,但是没有初始化的变量,这些变量在程序运行之前不需要占用存储器的空间。

5)堆(heap)

堆内存只在程序运行时出现,一般由程序员分配和释放。在具有操作系统的情况下,如果程序没有释放,操作系统可能在程序(例如一个进程)结束后会后内存。

6)栈(statck)

堆内存只在程序运行时出现,在函数内部使用的变量,函数的参数以及返回值将使用栈空间,栈空间由编译器自动分配和释放。


3、代码段、只读数据段、读写数据段、未初始化数据段属于静态区域,而堆和栈属于动区域。代码段、只读数据段和读写数据段将在连接之后产生,未初始化数据段将在程序初始化的时候开辟,而对堆和栈将在程序饿运行中分配和释放。

4、C语言程序分为映像和运行时两种状态。在编译-连接后形成的映像中,将只包含代码段(Text)、只读数据段(R0 Data)和读写数据段(RW Data)。在程序运行之前,将动态生成未初始化数据段(BSS),在程序的运行时还将动态生成堆(Heap)区域和栈(Stack)区域。

注:

1、一般来说,在静态的映像文件中,各个部分称之为节(Section),而在运行时的各个部分称之为段(Segment)。如果不详细区分,统称为段。

2、C语言在编译连接后,将生成代码段(TEXT),只读数据段(RO Data)和读写数据段(RW Data)。在运行时,除了上述三个区域外,还包括未初始化数据段(BBS)区域和堆(heap)区域和栈(Stack)区域。

三、C语言程序的段

1、段的分类

每一个源程序生成的目标代码将包含源程序所需要表达的所有信息和功能。目标代码中各段生成情况如下:

1)代码段(Code)

代码段由程序中的各个函数产生,函数的每一个语句将最终经过编译和汇编生成二进制机器代码

2)只读数据段(RO Data)

只读数据段由程序中所使用的数据产生,该部分数据的特点在运行中不需要改变,因此编译器会将数据放入只读的部分中。C语言的一些语法将生成只读数据数据段。

2、只读数据段(RO Data)

只读数据段(RO Data)由程序中所使用的数据产生,该部分数据的特点是在运行中不需要改变,因此编译器会将数据放入只读的部分中。以下情况将生成只读数据段。

1)只读全局变量

定义全局变量const char a[100]=”abcdefg”将生成大小为100个字节的只读数据区,并使用字符串“abcdefg”初始化。如果定义为const char a[]=”abcdefg”,没有指定大小,将根据“abcdefgh”字串的长度,生成8个字节的只读数据段。

2)只读局部变量

例如:在函数内部定义的变量const char b[100]=”9876543210”;其初始化的过程和全局变量。

3)程序中使用的常量

例如:在程序中使用printf("informationn”),其中包含了字串常量,编译器会自动把常量“information n”放入只读数据区。

注:在const char a[100]={“ABCDEFG”}中,定义了100个字节的数据区,但是只初始化了前面的8个字节(7个字符和表示结束符的‘0’)。在这种用法中,实际后面的字节米有初始化,但是在程序中也不能写,实际上没有任何用处。因此,在只读数据段中,一般都需要做完全的的初始化。

3、读写数据段(RW Data)

读写数据段表示了在目标文件中一部分可以读也可以写的数据区,在某些场合它们又被称为已初始化数据段。这部分数据段和代码,与只读数据段一样都属于程序中的静态区域,但是具有科协的特点。

1)已初始化全局变量

例如:在函数外部,定义全局的变量char a[100]=”abcdefg”

2)已初始化局部静态变量

例如:在函数中定义static char b[100]=”9876543210”。函数中由static定义并且已经初始化的数据和数组将被编译为读写数据段。

说明:

读写数据区的特点是必须在程序中经过初始化,如果只有定义,没有初始值,则不会生成读写数据区,而会定义为未初始化数据区(BSS)。如果全局变量(函数外部定义的变量)加入static修饰符,写成static char a[100]的形式,这表示只能在文件内部使用,而不能被其他文件使用。

4、未初始化数据段(BSS)

未初始化数据段常被称之为BSS(英文名为Block start by symbol的缩写)。与读写数据段类似,它也属于静态数据区。但是该段中数据没有经过初始化。因此它只会在目标文件中被标识,而不会真正称为目标文件中的一个段,该段将会在运行时产生。未初始化数据段只有在运行的初始化阶段才会产生,因此它的大小不会影响目标文件的大小。

四、在C语言的程序中,对变量的使用需要注意的问题

1、在函数体中定义的变量通常是在栈上,不需要在程序中进行管理,由编译器处理。

2、用malloc,calloc,realoc等分配分配内存的函数所分配的内存空间在堆上,程序必须保证在使用后使用后freee释放,否则会发生内存泄漏。

3、所有函数体外定义的是全局变量,加了static修饰符后的变量不管在函数内部或者外部存放在全局区(静态区)。

4、使用const定义的变量将放于程序的只读数据区。

说明:

在C语言中,可以定义static变量:在函数体内定义的static变量只能在该函数体内有效;在所有函数体外定义的static变量,也只能在该文件中有效,不能在其他源文件中使用;对于没有使用 static修饰的全局变量,可以在其他的源文件中使用。这些区别是编译的概念,即如果不按要求使用变量,编译器会报错。使用static 和没使用static修饰的全局变量最终都将放置在程序的全局去(静态去)。

五、程序中段的使用

C语言中的全局区(静态区),实际上对应着下述几个段:

只读数据段:RO Data

读写数据段:RW Data

未初始化数据段:BSS Data

一般来说,直接定义的全局变量在未初始化数据区,如果该变量有初始化则是在已初始化数据区(RW Data),加上const修饰符将放置在只读区域(RO Data).

例如:

const char ro[ ]=”this is a readonlydata”; //只读数据段,不能改变ro数组中的内容,ro存放在只读数据段。

char rw1[ ]=”this is global readwrite data”; //已初始化读写数据段,可以改变数组rw1中的内容。应为数值/是赋值不是把”this is global readwrite data” 地址给了rw1,不能改变char rw1[ ]=”this is global readwrite data”; //已初始化读写数据段,可以改变数组rw1中的内容。应为数值/是赋值不是把”this is global readwrite data” 地址给了rw1,不能改变”this is global readwrite data”的数值。因为起是文字常量放在只读数据段中

char bss_1[100];//未初始化数据段

const char *ptrconst = “constant data”; //”constant data”放在只读数据段,不能改变ptrconst中的值,因为其是地址赋值。ptrconst指向存放“constant data”的地址,其为只读数据段。但可以改变ptrconst地址的数值,因其存放在读写数据段中。

实例讲解:

int main( )

{

short b;//b放置在栈上,占用2个字节

char a[100];//需要在栈上开辟100个字节,a的值是其首地址

char s[]=”abcde”;

//s在栈上,占用4个字节,“abcde”本身放置在只读数据存储区,占6字节。s是一个地址

//常量,不能改变其地址数值,即s++是错误的。

char *p1;//p1在栈上,占用4个字节

char *p2 ="123456";//"123456"放置在只读数据存储区,占7个字节。p2在栈上,p2指向的内容不能更

//改,但是p2的地址值可以改变,即p2++是对的。

static char bss_2[100]; //局部未初始化数据段

static int c=0 ; //局部(静态)初始化区

p1 = (char *)malloc(10*sizeof(char)); //分配的内存区域在堆区

strcpy(p1,”xxx”); //”xxx”放置在只读数据存储区,占5个字节

free(p1); //使用free释放p1所指向的内存

return 0;

}

说明:

1、只读数据段需要包括程序中定义的const型的数据(如:const char ro[]),还包括程序中需要使用的数据如“123456”。对于const char ro[]和const char * ptrconst的定义,它们指向的内存都位于只读数据据区,其指向的内容都不允许修改。区别在于前者不允许在程序中修改ro的值,后者允许在程序中修改ptrconst本身的值。对于后者,改写成以下的形式,将不允许在程序中修改ptrconst本身的值:

const char * const ptrconst = “const data”;

2、读写数据段包含了已经初始化的全局变量static char rw1[]以及局部静态变量static char

rw2[]。rw1和rw2的差别在于编译时,是在函数内部使用的还是可以在整个文件中使用。对于前者,static修饰在于控制程序的其他文件时候可以访问rw1变量,如果有static修饰,将不能在其他的C语言源文件中使用rw1,这种影响针对编译-连接的特性,但无论有static,变量rw1都将被放置在读写数据段。对于后者rw2,它是局部的静态变量,放置在读写数据区;如果不使用static修饰,其意义将完全改变,它将会是开辟在栈空间局部变量,而不是静态变量。

3、未初始化数据段,事例1中的bss_1[100]和 bss_2[200]在程序中代表未初始化的数据段。其区别在于前者是全局的变量,在所有文件中都可以使用;后者是局部的变量,只在函数内部使用。未初始化数据段不设置后面的初始化数值,因此必须使用数值指定区域的大小,编译器将根据大小设置BBS中需要增加的长度。

4、栈空间包括函数中内部使用的变量如short b和char a[100],以及char *p1中p1这个变量的值。

1)变量p1指向的内存建立在堆空间上,堆空间只能在程序内部使用,但是堆空间(例如p1指向的内存)可以作为返回值传递给其他函数处理。

2)栈空间主要用于以下3类数据的存储:

a、函数内部的动态变量

b、函数的参数

c、函数的返回值

3)栈空间主要的用处是供函数内部的动态变量使用,变量的空间在函数开始之前开辟,在函数退出后由编译器自动回收。看一个例:

int main( )

{

char *p = "tiger";

p[1] = 'I';

p++;

printf("%sn",p);

}

编译后提示:段错误

分析:

char *p = "tiger";系统在栈上开辟了4个字节存储p的数值。"tiger"在只读存储区中存储,因此"tiger"的内容不能改变,*p="tiger",表示地址赋值,因此,p指向了只读存储区,因此改变p指向的内容会引起段错误。但是因为p是存放在栈上,因此p的数值是可以改变的,因此p++是正确的。

六、const的使用

1、前言:

const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程序上可以提高程序的健壮性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解别人的程序有所帮助。

2、const变量和常量

1)const修饰的变量,其值存放在只读数据段中,其值不能被改变。称为只读变量。

其形式为 const int a=5;此处可以用a代替5

2)常量:其也存在只读数据段中,其数值也不能被改变。其形式为"abc" ,5

3、const 变量和const限定的内容,先看一个事例:

typedef char* pStr;

int main( )

{

char string[6] = “tiger”;

const char *p1 = string;

const pStr p2 = string;

p1++;

p2++;

printf(“p1=%snp2=%sn”,p1,p2);

}

程序经过编译后,提示错误为

error:increment of read-only variable ‘p2’

1)const 使用的基本形式为:const char m;

//限定m 不可变

2)替换1式中的m,const char *pm;

//限定*pm不可变,当然pm是可变的,因此p1++是对的。

3)替换1式中的char,const newType m;

//限定m不可变,问题中的pStr是一种新类型,因此问题中p2不可变,p2++是错误的。

4、const 和指针

类型声明中const用来修饰一个常量,有如下两种写法:

1)const在前面

const int nValue;//nValue是const

const char *pContent;//*pContent是const,pConst可变

const (char *)pContent;//pContent是const,*pContent可变

char *const pContent;//pContent是const,*pContent可变

const char * const pContent;//pContent和*pContent都是const

2)const 在后面与上面的声明对等

int const nValue;// nValue是const

char const *pContent;//*pContent是const, pContent可变

(char *) constpContent;//pContent是const, *pContent可变

char* const pContent;// pContent是const, *pContent可变

char const* const pContent;//pContent和*pContent都是const

说明:const和指针一起使用是C语言中一个很常见的困惑之处,下面是两天规则:

1)沿着*号划一条线,如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。你可以根据这个规则来看上面声明的实际意义,相信定会一目了然。

2)对于const (char *) ; 因为char *是一个整体,相当于一个类型(如char),因此,这是限定指针是const。

七、单片机C语言中的data,idata,xdata,pdata,code

从数据存储类型来说,8051系列有片内、片外程序存储器,片内、片外数据存储器,片内程序存储器还分直接寻址区和间接寻址类型,分别对应code、data、xdata、idata以及根据51系列特点而设定的pdata类型,使用不同的存储器,将使程序执行效率不同,在编写C51程序时,最好指定变量的存储类型,这样将有利于提高程序执行效率(此问题将在后面专门讲述)。与ANSI-C稍有不同,它只分SAMLL、COMPACT、LARGE模式,各种不同的模式对应不同的实际硬件系统,也将有不同的编译结果。

在51系列中data,idata,xdata,pdata的区别:

data:固定指前面0x00-0x7f的128个RAM,可以用acc直接读写的,速度最快,生成的代码也最小。

idata:固定指前面0x00-0xff的256个RAM,其中前128和data的128完全相同,只是因为访问的方式不同。idata是用类似C中的指针方式访问的。汇编中的语句为:mox ACC,@Rx.(不重要的补充:c中idata做指针式的访问效果很好)

xdata:外部扩展RAM,一般指外部0x0000-0xffff空间,用DPTR访问。

pdata:外部扩展RAM的低256个字节,地址出现在A0-A7的上时读写,用movx ACC,@Rx读写。这个比较特殊,而且C51好象有对此BUG,建议少用。但也有他的优点,具体用法属于中级问题,这里不提。

单片机C语言unsigned char code table[]code 是什么作用?

code的作用是告诉单片机,我定义的数据要放在ROM(程序存储区)里面,写入后就不能再更改,其实是相当与汇编里面的寻址MOVX(好像是),因为C语言中没办法详细描述存入的是ROM还是RAM(寄存器),所以在软件中添加了这一个语句起到代替汇编指令的作用,对应的还有data是存入RAM的意思。

程序可以简单的分为code(程序)区,和data (数据)区,code区在运行的时候是不可以更改的,data区放全局变量和临时变量,是要不断的改变的,cpu从code区读取指令,对data区的数据进行运算处理,因此code区存储在什么介质上并不重要,象以前的计算机程序存储在卡片上,code区也可以放在rom里面,也可以放在ram里面,也可以放在flash里面(但是运行速度要慢很多,主要读flash比读ram要费时间),因此一般的做法是要将程序放到flash里面,然后load到 ram里面运行的;DATA区就没有什么选择了,肯定要放在RAM里面,放到rom里面改动不了。

bdata如何使用它呢?

若程序需要8个或者更多的bit变量,如果你想一次性给8个变量赋值的话就不方便了,(举个例子说说它的方便之处,想更深入的了解请在应用中自己琢磨)又不可以定义bit数组,只有一个方法

char bdata MODE;

sbit MODE_7 = MODE^7;

sbit MODE_6 = MODE^6;

sbit MODE_5 = MODE^5;

sbit MODE_4 = MODE^4;

sbit MODE_3 = MODE^3;

sbit MODE_2 = MODE^2;

sbit MODE_1 = MODE^1;

sbit MODE_0 = MODE^0;

8个bit变量MODE_n 就定义好了

这是定义语句,Keilc 的特殊数据类型。记住一定要是sbit

不能 bit MODE_0 = MODE^0;

赋值语句要是这么写C语言就视为异或运算。

Flash相对单片机里的RAM属于外部存取器,虽其结构位置装在单片机中,其实xdata是放在相对RAM的外面,而flash正是相对RAM外面。

inta变量定义在内部RAM,xdatainta定义在外部RAM或flash,uchar codea定义在flash。

uchar code duma[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40,0x00}; //共阴的数码管段选,P2口要取的数值

若定义 uchar aa[5],aa[5]中的内容是存放在数据存储区(RAM)中的,在程序运行工程中各个数组元素的值可以被修改,掉电后aa[5]中的数据无法保存。

若定义 uchar code bb[5]中的内容是存放在程序存储区(如flash)中的,只有在烧写程序时,才能改变bb[5]中的各元素的值,在程序运行工程中无法修改,并且掉电后bb[5]中的数据不消失。

八、C语言中堆和栈的区别

C语言程序经过编译连接后形成编译、连接后形成的二进制映像文件由栈、堆、数据段(由三部分部分组成:只读数据段,已经初始化读写数据段,未初始化数据段即BBS)和代码段组成,如下图所示:


1、栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量等值。其操作方式类似于数据结构中的栈。

2、堆区(heap):一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。注堆和数据结构中的堆栈不一样,其类是与链表。

3、程序代码区:存放函数体的二进制代码。

4、数据段:由三部分组成:

1)只读数据段:

只读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。一般是const修饰的变量以及程序中使用的文字常量一般会存放在只读数据段中。

2)已初始化的读写数据段:

已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并且有初值,以供程序运行时读写。在程序中一般为已经初始化的全局变量,已经初始化的静态局部变量(static修饰的已经初始化的变量)

3)未初始化段(BSS):

未初始化数据是在程序中声明,但是没有初始化的变量,这些变量在程序运行之前不需要占用存储器的空间。与读写数据段类似,它也属于静态数据区。但是该段中数据没有经过初始化。未初始化数据段只有在运行的初始化阶段才会产生,因此它的大小不会影响目标文件的大小。在程序中一般是没有初始化的全局变量和没有初始化的静态局部变量。

堆和栈的区别

1、申请方式

(1)栈(satck):由系统自动分配。例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间。

(2)堆(heap):需程序员自己申请(调用malloc,realloc,calloc),并指明大小,并由程序员进行释放。容易产生memory leak.

eg:charp;

p = (char *)malloc(sizeof(char));//但是,p本身是在栈中。

2、申请大小的限制

1)栈:在windows下栈是向底地址扩展的数据结构,是一块连续的内存区域(它的生长方向与内存的生长方向相反)。栈的大小是固定的。如果申请的空间超过栈的剩余空间时,将提示overflow。

2)堆:堆是高地址扩展的数据结构(它的生长方向与内存的生长方向相同),是不连续的内存区域。这是由于系统使用链表来存储空闲内存地址的,自然是不连续的,而链表的遍历方向是由底地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。

3、系统响应:

1)栈:只要栈的空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

2)堆:首先应该知道操作系统有一个记录空闲内存地址的链表,但系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的free语句才能正确的释放本内存空间。另外,找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

说明:对于堆来讲,对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,

4、申请效率

1)栈由系统自动分配,速度快。但程序员是无法控制的

2)堆是由malloc分配的内存,一般速度比较慢,而且容易产生碎片,不过用起来最方便。

5、堆和栈中的存储内容

1)栈:在函数调用时,第一个进栈的主函数中后的下一条语句的地址,然后是函数的各个参数,参数是从右往左入栈的,然后是函数中的局部变量。注:静态变量是不入栈的。

当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续执行。

2)堆:一般是在堆的头部用一个字节存放堆的大小。

6、存取效率

1)堆:char *s1=”hellowtigerjibo”;是在编译是就确定的

2)栈:char s1[]=”hellowtigerjibo”;是在运行时赋值的;用数组比用指针速度更快一些,指针在底层汇编中需要用edx寄存器中转一下,而数组在栈上读取。

补充:

栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

7、分配方式:

1)堆都是动态分配的,没有静态分配的堆。

2)栈有两种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的。它的动态分配是由编译器进行释放,无需手工实现。

来源:玩转单片机

围观 63

在常用传感器中,模数转换器是其中至关重要的环节,模数转换器的精度以及系统的成本直接影响到系统的实用性。因此。如何提高模数转换器的精度和降低系统的成本是衡量系统是否具有实际应用价值的标准。

图1:ADC工作流程

一、ADC简单介绍

ADC可分为SAR型、积分型、Σ-Δ型、折叠型等方式。SAR ADC因其功耗低、精度高、面积小等特点而被用于超大规模IC和片上系统中。SAR ADC的精度是关键参数。SAR ADC有采样、量化和编码等三种功能。三种功能中,采样最重要。采样的精确性决定了ADC的转换精度。逐次逼近型 ADC 中电路模块主要包括:S/H 电路、电容阵列、比较器、逐次逼近控制逻辑、时钟及偏置电路等,而 S/H 电路、电容阵列、比较器是高精度逐次逼近型 ADC 设计的关键。

首先由采祥保持电路采集并保持某点信号一段时间,在保持的这段时间里,对该点信号进行量化处理,以0或1数字编码形式输出,该串数字码与不同权重的参考电压相乘再相加,就是该点的电压值。按照这种方式,每隔一定周期就可以量化连续的模拟信号某点的电压值,采样点越多,还原的模拟信号就会越精确。

图 2 不同ADC架构性能总结

ADC的精度是整个电路和系统精度至关重要的部分。ADC的精度和分辨率是两个不同的概念。精度指转换后所得结果相对与实际值的准确度;分辨率是指转换器所能分辨的模拟信号的最小变化值。一般来讲,分辨率越高,转换误差越小;但影响精度的因素较多,分辨率很高的ADC,可能并不一定具有很高的精度。

所谓嵌入式模数转换器是指将模拟多路开关、采样保持、A/D转换、微控制器集成在一个芯片上。经常采用逐次比较型进行A/D转换,模拟输入信号一般为非负单极性。且输入信号的电压范围为0~AVREF。

二、影响ADC精度参数

在验证ADC性能的时候,可以通过相关参数衡量其性能优劣,这些参数大体分为两大类,即静态参数和动态参数。

1、ADC静态特性参数

静态特性与时间无关,它是指实际量化特性与理想量化特性之间存在的偏差,包括:积分非线性误差(Integral Non-Linearity:INL)、微分非线性误差(Differential Non-Linearity; DNL)、增益误差(Gain error)、失调误差(Offset error)、分辨率(resolution)。

(1)增益误差(Gain error)

ADC 模块的输入、输出是线性关系。但实际上, ADC模块是存在增益误差和偏移误差的, 其中增益误差是实际曲线斜率和理想曲线斜率之间的偏差, 偏移误差(或失调误差)是0 V输入时实际输出值与理想输出值(0 V)之间的偏差。


(2)积分非线性误差(Integral Non-Linearity:INL)

模数转换器的积分非线性误差用来衡量实际特性曲线与理想特性曲线的最大差值,它表示了实际有限精度曲线相对与理想有限精度曲线的偏移量,可以用来估算谐波失真,通常以百分数或LSB为单位。


(3)微分非线性误差(DNL)

微分非线性误差为每个量化阶梯上测量的相邻编码之间的距离,通常是由电路元器件的非理想因素引入的模拟増量偏移值,以百分比或LSB为单位。


2、ADC动态特性参数

ADC的动态特性参数通常与ADC的转换速率和输入信号频率相关。主要包括:信噪比(SNR)、信噪失真比(SNDR)、无杂散动态范围(SFDR)、总谐波失真(THD)、有效位数(ENOB)。

3、温度湿度环境及电源电压的波动引起的误差、采样电压的波动

在实际应用中,由于环境温度、湿度等参数的变化可能会引入一些误差。电源电压的不稳定也会带来一定的误差,采样电压的波动(可能是由于高频信号叠加,或者其他随机干扰信号),对整个系统的精度产生影响,电源电压变化引起的转换误差在高精度要求场合不可忽略。

4、其他因素

模数转换器(ADC)想要在实际应用中达到标称的精度,仅仅依赖ADC模块本身是不够的,实际的测量精度还会受到一系列外在因素的影响,例如:

•ADC时间配置(包括采集时间、转换时间、采样时间、采样时钟抖动等等)

•电源性能(噪声和内部阻抗)

•数据采集系统中数字和模拟部分的隔离情况

•内部阻抗与外部阻抗的匹配

•输入/输出开关切换的影响

•PCB布局布线

三、提高ADC精度方法

软件算法提高精度(常用的方法)

在运用具有内置模数转换模块的嵌入式单片机来进行模数转换的过程中,为了提高分辨率或对微弱信号采样识别,目前比较常用的方法主要是采用过采样技术来实现低于最小采样分辨率的微弱信号采样。该技术是通过多次对输入的采样信号叠加白噪声后,再模数转换输出,然后对输出取平均值。 在采样过程中,导致采样电压波动的因素有很多。可能是由于外界的随机信号干扰引起。也可能是由于电路中产生的谐波信号引起的周期性干扰信号。用软件滤波方法则可以有效减小此类误差。常用滤波算法如下:

算术平均滤波法

递推平均滤波法(又称滑动平均滤波法)

中值滤波法

一阶滞后滤波法

加权平均滤波法

针对环境及电压波动解决方案如下:

(1)采用高精度稳定电源供给,减少电源电压变化误差。

基准电压是提供ADC转换时的参考电压,是保证转换精度的基本条件。在要求较高精度时,基准电压要考虑单独用高精度稳定电源供给。此外,外加模拟电源和数字电源也要尽量采用稳定性高(电源电压敏感度<0.002%)、受温度变化小的电源。当然可以选择温度系数比较好、精度比较高的电源模块提供稳定的电压。但是由于高精度的电源管理模块价格往往不菲,会大大增加系统的成本。在本设计中,采用市场上面比较常见的LDO作为电源电压。

(2) 利用数学变换减小运算误差,减小温度漂移、湿度、环境等及电源电压的波动引起的误差。




(3)利用软件滤波方法。

针对增益误差和偏移误差解决方案如下:

(1)最小二乘法和一元线性回归(直线拟合问题) 用稳定信号源产生多个标准电压, 通过输入ADC通道记录采样值。然后利用最小二乘和一元线性回归思想处理数据, 求出的拟合最佳曲线, 使得各个坐标点到该最佳曲线的距离的平方和(残差平方和)最小。

(2)在用计算机对模拟信号采集情况下,将编码器零电平信号读入计算机内存中相应的单元,然后才开始采样程序的执行。在采样程序中,将采集到的数据与零电平相减,从而基本上消除偏移温漂误差。

ADC时间配置

在器件中,采样时间等于一个ADC时钟周期。该ADC模块的采样时间不仅依赖于ADC时钟,还与其他配置有关,如NXP芯片中可以通过修改ADCx_CFG1寄存器中的ADLSMP位和ADCx_CFG2寄存器中的ADLSTS位来对采样时间进行配置。因此,总的转换时间并不会随采样时间增加而显著增加,这种特性在高输入阻抗的情况下尤其有用。

ADC硬件处理

为了使ADC达到最佳的性能,我们需要正确地设计和配置整个系统。在硬件方面,可进行以下配置,例如: • 在芯片电源引脚间放置0.1uF的电容,电容应尽可能地贴近芯片封装(每对电源引脚间放置一个电容)

•在芯片电源引脚间放置约为100uF的电容

•PCB走线长度应该尽量短 •在实际应用设计中应充分考虑PCB走线上寄生参数的影响

•必须小心处理模拟电源以及参考引脚,使它们的噪声幅度最小 •针对数字部分和模拟部分使用不同的供电电源和地平面

•如果数字部分和模拟部分连接到了相同的供电电源,则应该在数字部分和模拟部分之间使用一个小的电感或磁珠进行连接

•使用地平面将有噪声的数字元件与模拟元件隔离开来,走线时用模拟地将模拟信号包围起来

外部RC元件的取值会从本质上影响ADC转换的精度,为了获得最佳的ADC性能,我们需要小心对待并设计外部RC元件,在选取采样时间时也必须参考采样电容充电的时间常数

本文转自:博客园 - 星空下聆听 ,转载此文目的在于传递更多信息,版权归原作者所有。

围观 516

为了让大家充分理解 UART 串口通信的原理,我们先把 P3.0 和 P3.1 当做 IO 口来进行模拟实际串口通信的过程,原理搞懂后,我们再使用寄存器配置实现串口通信过程。

对于 UART 串口波特率,常用的值是 300、600、1200、2400、4800、9600、14400、19200、28800、38400、57600、115200 等速率。IO 口模拟 UART 串行通信程序是一个简单的演示程序,我们使用串口调试助手下发一个数据,数据加 1 后,再自动返回。

串口调试助手,这里我们直接使用 STC-ISP 软件自带的串口调试助手,先把串口调试助手的使用给大家说一下,如图 11-6 所示。第一步要选择串口助手菜单,第二步选择十六进制显示,第三步选择十六进制发送,第四步选择 COM 口,这个 COM 口要和自己电脑设备管理器里的那个 COM 口一致,波特率按我们程序设定好的选择,我们程序中让一个数据位持续时间是 1/9600 秒,那这个地方选择波特率就是选 9600,校验位选 N,数据位 8,停止位 1。

图 11-6 串口调试助手示意图

串口调试助手的实质就是利用电脑上的 UART 通信接口,发送数据给我们的单片机,也可以把我们的单片机发送的数据接收到这个调试助手界面上。

因为初次接触通信方面的技术,所以我把后面的 IO 模拟串口通信程序进行一下解释,大家可以边看我的解释边看程序,把底层原理先彻底弄懂。

变量定义部分就不用说了,直接看 main 主函数。首先是对通信的波特率的设定,在这里我们配置的波特率是 9600,那么串口调试助手也得是 9600。配置波特率的时候,我们用的是定时器 T0 的模式 2。模式 2 中,不再是 TH0 代表高 8 位,TL0 代表低 8 位了,而只有TL0 在进行计数,当 TL0 溢出后,不仅仅会让 TF0 变 1,而且还会将 TH0 中的内容重新自动装到 TL0 中。这样有一个好处,就是我们可以把想要的定时器初值提前存在 TH0 中,当 TL0溢出后,TH0 自动把初值就重新送入 TL0 了,全自动的,不需要程序中再给 TL0 重新赋值了,配置方式很简单,大家可以自己看下程序并且计算一下初值。

波特率设置好以后,打开中断,然后等待接收串口调试助手下发的数据。接收数据的时候,首先要进行低电平检测 while (PIN_RXD),若没有低电平则说明没有数据,一旦检测到低电平,就进入启动接收函数 StartRXD()。接收函数最开始启动半个波特率周期,初学可能这里不是很明白。大家回头看一下我们的图 11-2 里边的串口数据示意图,如果在数据位电平变化的时候去读取,因为时序上的误差以及信号稳定性的问题很容易读错数据,所以我们希望在信号最稳定的时候去读数据。除了信号变化的那个沿的位置外,其它位置都很稳定,那么我们现在就约定在信号中间位置去读取电平状态,这样能够保证我们读的一定是正确的。

一旦读到了起始信号,我们就把当前状态设定成接收状态,并且打开定时器中断,第一次是半个周期进入中断后,对起始位进行二次判断一下,确认一下起始位是低电平,而不是一个干扰信号。以后每经过 1/9600 秒进入一次中断,并且把这个引脚的状态读到 RxdBuf 里边。等待接收完毕之后,我们再把这个 RxdBuf 加 1,再通过 TXD 引脚发送出去,同样需要先发一位起始位,然后发 8 个数据位,再发结束位,发送完毕后,程序运行到 while (PIN_RXD),等待第二轮信号接收的开始。

#include <reg52.h>

sbit PIN_RXD = P3^0; //接收引脚定义

sbit PIN_TXD = P3^1; //发送引脚定义

bit RxdOrTxd = 0; //指示当前状态为接收还是发送

bit RxdEnd = 0; //接收结束标志

bit TxdEnd = 0; //发送结束标志

unsigned char RxdBuf = 0; //接收缓冲器

unsigned char TxdBuf = 0; //发送缓冲器

void ConfigUART(unsigned int baud);

void StartTXD(unsigned char dat);

void StartRXD();

void main(){

EA = 1; //开总中断

ConfigUART(9600);

while (1){ //配置波特率为 9600

while (PIN_RXD); //等待接收引脚出现低电平,即起始位

StartRXD(); //启动接收

while (!RxdEnd); //等待接收完成

StartTXD(RxdBuf+1); //接收到的数据+1 后,发送回去

while (!TxdEnd); //等待发送完成

}

}

/* 串口配置函数,baud-通信波特率 */

void ConfigUART(unsigned int baud){

TMOD &= 0xF0; //清零 T0 的控制位

TMOD |= 0x02; //配置 T0 为模式 2

TH0 = 256 - (11059200/12)/baud; //计算 T0 重载值

}

/* 启动串行接收 */

void StartRXD(){

TL0 = 256 - ((256-TH0)>>1); //接收启动时的 T0 定时为半个波特率周期

ET0 = 1; //使能 T0 中断

TR0 = 1; //启动 T0

RxdEnd = 0; //清零接收结束标志

RxdOrTxd = 0; //设置当前状态为接收

}

/* 启动串行发送,dat-待发送字节数据 */

void StartTXD(unsigned char dat){

TxdBuf = dat; //待发送数据保存到发送缓冲器

TL0 = TH0; //T0 计数初值为重载值

ET0 = 1; //使能 T0 中断

TR0 = 1; //启动 T0

PIN_TXD = 0; //发送起始位

TxdEnd = 0; //清零发送结束标志

RxdOrTxd = 1; //设置当前状态为发送

}

/* T0 中断服务函数,处理串行发送和接收 */

void InterruptTimer0() interrupt 1{

static unsigned char cnt = 0; //位接收或发送计数

if (RxdOrTxd){ //串行发送处理

cnt++;

if (cnt <= 8){ //低位在先依次发送 8bit 数据位

PIN_TXD = TxdBuf & 0x01;

TxdBuf >>= 1;

}else if (cnt == 9){ //发送停止位

PIN_TXD = 1;

}else{ //发送结束

cnt = 0; //复位 bit 计数器

TR0 = 0; //关闭 T0

TxdEnd = 1; //置发送结束标志

}

}else{ //串行接收处理

if (cnt == 0){ //处理起始位

if (!PIN_RXD){ //起始位为 0 时,清零接收缓冲器,准备接收数据位

RxdBuf = 0;

cnt++;

}

}else{ //起始位不为 0 时,中止接收

TR0 = 0; //关闭 T0

}else if (cnt <= 8){ //处理 8 位数据位

RxdBuf >>= 1; //低位在先,所以将之前接收的位向右移

//接收脚为 1 时,缓冲器最高位置 1,

//而为 0 时不处理即仍保持移位后的 0

if (PIN_RXD){

RxdBuf |= 0x80;

}

cnt++;

}else{ //停止位处理

cnt = 0; //复位 bit 计数器

TR0 = 0; //关闭 T0

if (PIN_RXD){ //停止位为 1 时,方能认为数据有效

RxdEnd = 1; //置接收结束标志

}

}

}

}

本文转自:C语言中文网
http://c.biancheng.net/cpp/html/1921.html

围观 306

(来自:Axiomtek | PDF

Axiomtek 刚刚推出了一款性能和扩展都远胜于树莓派的 3.5 英寸 CAPA13R 单板机,其采用了嵌入式的 AMD 锐龙 APU 方案、集成了 Vega 核显、支持外接四台显示器,但体型依然相当小巧。感兴趣的朋友可选择两种配置,其中高端版本采用了锐龙 V1707B APU,集成 Vega11 核显,可轻松应对 4K 视频和 3D 渲染。

普通版本采用了锐龙 V1605B APU,集成 Vega8 核显,主要面向负载相对较轻的工作。内存方面,高低配分别支持单条 DDR4-3200 或 DDR4-2400 的 SO-DIMM 运存(最高 16GB)。

Axiomtek 嵌入式主板与技术业务部产品经理 Michelle 表示:“AMD 锐龙 V1000 系列 APU 是需要高分辨率显示和完整图形功能的嵌入式解决方案的最佳选择,同时具有占地面积更小的优势”。


该系列单板机提供了多个 GbE 以太网直连接口,但也支持 Wi-Fi 适配器,另有 PCIe x1 的 M.2 插槽。

提供了 SATA、USB 2.0、USB 3.1 Gen 2,两个 HDMI + 一个 DP 视频输出,以及 LVDS 和 HD 音频接口。


目前 CAPA13R 嵌入式锐龙 V1000 系列单板机已经上市,但 Axiomtek 尚未公布价格信息。

配置方面,两款 CAPA13R 还提供了四种标准配置和多种可选配置,感兴趣的朋友可移步至官网查看。

来源:cnBeta.COM

围观 7

很多人都认为,单机片和CPU不是属于两种不同的东西吗?他们怎么可以拿来比较,其实有专业人士就知道单机片和CPU 的关系可以说是十分的密切。本文来分享一下,他们到底隐藏着什么秘密。

什么是单片机,相信很多人都还不知道。也不知道单片机的作用是什么。单片机简称为单片微控制器(Microcontroler),它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上,相当于一个微型的计算机,因为它最早被用在工业控制领域。单片机由芯片内仅有CPU的专用处理器发展而来。最早的设计理念是通过将大量外围设备和CPU集成在一个芯片中,使计算机系统更小,更容易集成进复杂的而对提及要求严格的控制设备当中。Intel的Z80是最早按照这种思想设计出的处理器,从此以后,单片机和专用处理器的发展便分道扬镳。

大家都知道我们的电脑主要是由中央处理单元CPU(进行运算、控制)、随机存储器RAM(数据存储)、存储器ROM(程序存储)、输入/输出设备I/O(串行口、并行输出口等)。安装在一个被称之为主板的印刷线路板上,就是我们个人的计算机了。

把单片机看成一个整体分成四块就很容易认识了。 把这些东西(CPU,硬盘,内存,主板等等)用集成块做好后,如下图所视:

就成了我们要学习的“单片机”了。而在单机片的内部,CPU,硬盘,内存,主板等等却又是另外的名字。

1)CPU(Central Processing Unit)。它是单片机的核心部件,包括运算器和控制器。运算器既是算术逻辑单元ALU(ArithmeTIc logic Unit),其功能是进行算术运算和逻辑运算。控制器一般由指令寄存器、指令译码器、时序电路和控制电路组成。起作用是完成取指令、将指令译码形成各种微操作并执行指令,同时控制计算机的各个部件有条不紊地工作。

2)计算机中的内存,在单片机里叫数据存储器,也叫随机存储器。用RAM(Random Access Memery)表示。其作用是用于存放运算的中间结果,数据暂存和缓冲,标志位等。特点是:掉电后会丢失数据。

3)计算机中的硬盘,在单片机中,叫程序存储器,也叫只读存储器。用ROM(Read only memery)表示。其作用和硬盘差不多,用来存放用户程序。特点是:掉电后不会丢失数据。

4)输入/输出设备I/O“主板”,在单片机里,叫做I/O(输入输出设备)当然也包含了串行口,并行口,定时器,记时器等等。

来源:网络转载

围观 134

单片机就是个小计算机,大计算机少不了的数据存储系统,单片机一样有,而且往往和CPU集成在一起,更加显得小巧灵活。

直到90年代初,国内容易得到的单片机就是8031:不带存储器的芯片,要想工作,还必须外加RAM和ROM,单片机成了3片机......

现在不同了,大的小的又是51,又是AVR又是STC,还有什么430,PIC等等,都各说各的好,可是谁也不敢说“我不要存储器”。

单片机的数据存储手段

程序存储器ROM

程序存储器里面存放的是单片机的灵魂:工作程序。

小的可能只有1KB,最多只能装1024条8位数据,因为实际指令还有许多2字节,3字节指令,所以它还装不下1024条指令。大的也有128KB的。这些8位数据,要么在工厂里做模子光刻进去,要么一次性的烧写进去。

业余或开发,最多也就是用编程器这么一个特殊工具,把调试成功的机器码装载进去,或者像AVR单片机那样自己花几块钱做一条下载线,把电脑里这些东西灌进去(或许是AVR最吸引人之处)。

它一旦进驻电脑的程序存储器中,除了借助上述装置便不能自由改写,在单片机运行时,只是从其中读出指令或固定的数据,所以给程序存储器一个“只读存储器”的别名,简写为ROM,包括用编程器写紫外线擦除内容的EPROM、用电擦除的EEPROM和现在新兴的FLASH ROM。

一次性写入的ROM,仅用于电路和程序固定的批量产品中,实际工作起来,都是一样的。

为了定位ROM中的数据,每个8位存储单元都有一个固定的“地址”,通常用16进制数表示。例如,对于一个所谓4K的ROM,地址从0000H到0FFFH(即从0000,0001...4095),单片机运行时从哪个地址取数据,完全由程序本身决定,并不要我们干预。

记住,给单片机一通电,它经过一个短暂的复位过程,立即转向ROM的最低地址0000H,在这里面放置的往往是一条“跳转”指令,它从这里一步跳到另一个地址:程序的真正起始地址,例如51机的0080H。

ROM是程序存储器,除了指令外,还包括运行程序必须的某些固定数据,例如:数据表。假如,我们要求在单片机的接口上输出00H到FFH(255)按正弦半波变化的数值,每秒10000次。如果硬要它按照公式一个个计算,对于它来说未免力不从心。可是我们可以把预先计算好的数值存入ROM中,到时候直接取出不是好多了?

又如一个重要的应用:大家一定见过不少单片机的东西上面都有数码显示,那些个数字其实就是用单片机的口线控制数码管的字段电极电位。这些字形也是存放在ROM中的字模表,各个字模和0-9的数字(机器内当然是0000-0101二进制数)对应起来。常见的共阳极7段数码管,必须在阳极加正电,7个阴极都是地电位,才能显示数字"8",数字8对应的显示字码值是二进制数“10000000“(那个1对应的是小数点,高电位不让它显示)。

数据存储器RAM

这是个可以随时存取数据的一块存储器,也就是可以读(取)也可以写(存)的存储器,简称RAM。

现在的单片机里面使用的RAM,属于静态RAM或SRAM,这个和电脑用的内存条有所不同。只要你把数据写入SRAM后,不断电或者不清除掉,这个数据就一直保存在那里。电脑用的是动态RAM,要不断给它加刷新脉冲才能保存数据。

因为单片机处理的信息量比电脑小很多,所以它带的RAM也比较少:从完全不带、带128、256、...1K、2K,到4K,比ROM少多了。

因为实际上RAM只是作为数据临时存放的地方,除非进行图像处理需要存放大量的数据外。一般对于执行较简单任务的单片机,有这么多也够用,如果实在不够用也只能采取外加SRAM如6116、6264等等来扩展。

为了对RAM单元存取8位二进制数,当然也得和ROM一样用“地址”来标示它的具体位置。假如某单片机有1K(1024)RAM,它的地址也是从0000到1024,或16进制数的0000H到03FFH。可见,和ROM的地址是一样的。

会不会混淆不清?

不会,因为读ROM是由单片机的程序指针或转移指令或查表指令进行,而这些指令是不会进入RAM区的;读写RAM是另外的数据传送指令,也不会进入ROM区。这点也是和电脑不同之处,后者程序和数据都在内存条里面,地址不同,如果窜位了就会造成不可预见后果。单片机的这种存储器结构也称为哈佛结构。

RAM在单片机里的用途

RAM在单片机里的用途,主要是存放临时数据。

例如用单片机测温,每秒测1次,显示1分钟的平均值(1分钟更新一次):

我们先通过传感器、放大电路、A/D转换,把温度这个模拟量转变为成比例的二进制数,然后每秒钟1次把数字量通过输入口顺序存入到单片机的RAM中,然后对他们进行两两求和再平均的计算,最后的数值显示出来,然后把这60个存储单元统统写0清除旧数据,下次又是如此循环进行。

结语

另外在单片机里面还有若干寄存器,数量不多但是作用很大,除了暂存数据,还可以交换、加工、传递等等,以及随时记录单片机当前处于什么状态,输入输出口也是作为特殊功能的寄存器存在,具体各有不同,就不是随便说说可以搞清楚的,要看有关书籍了。

围观 9

新一代AVR MCU系列搭载独立于内核的外设、具备先进模拟和片上通信功能

随着物联网(IoT)为工业和家庭应用提供更强的连接性,以及车联网提升了驾驶室和操控功能,业界需要更高性能的单片机来实现更好的实时控制以及增强的人机接口应用。Microchip Technology Inc.(美国微芯科技公司)今日宣布推出下一代AVR® DA系列单片机(MCU),是其首款带有外设触摸控制器(PTC)的功能安全型AVR MCU系列。

Microchip 8位单片机事业部助理营销副总裁Greg Robinson表示:“新推出的AVR DA单片机系列继承了Microchip高性能和高代码效率器件的优势,通过搭载先进模拟和独立于内核的外设,以及比现有器件更多的电容式触摸通道,满足了多个行业的新需求。新的单片机系列产品广泛应用于智能家居安全、楼宇自动化、传感器系统等应用,以及汽车和工业自动化等领域,助力开发人员设计出更加强大、精确和响应灵敏的各类应用。”

Microchip的功能安全认证适用于具有最新安全特性的器件,这些器件同时还带有安全手册、故障模式、影响与诊断分析(FMEDA)报告,在某些情况下,还具备诊断软件,从而减少终端应用安全认证的时间和成本。AVR DA MCU系列包括多个集成的安全功能,以确保稳健的运行,诸如上电复位、欠压检测器和电压水平监控器,可确保充足的电源电压。循环冗余校验(CRC)扫描确保闪存中的应用程序代码有效。通过确保代码的完整性,可避免应用程序的意外和潜在的不安全行为。

Microchip的新型AVR DA系列MCU可在全电源电压范围内实现24 MHz的CPU速度、存储密度高达128 KB的闪存、16 KB SRAM和512 字节EEPROM,具备12位差分ADC、10位DAC、模拟比较器和过零检测器。PTC支持电容式触摸接口设计,支持按钮、滑动条、滚轮、触摸板、较小型触摸屏及广泛应用于消费和工业产品和车辆的手势控制。AVR DA系列支持多达46个自电容和529个互电容触摸通道,并采用最新一代增强型驱动屏蔽PTC和升压模式技术,提供增强的抗噪性、耐水性、触摸灵敏度和响应时间。

此外,AVR DA 系列MCU为嵌入式实时控制系统带来了额外的价值。集成事件系统支持外设间无需CPU即可进行通信。事件无延迟,信息不会丢失,为进行可靠和安全的设计提供了增强的实时性能和可预测性。通过减少CPU需要激活的时间,应用程序的总功耗得以降低。

可配置的自定义逻辑外设支持内部逻辑功能设置,无需外部元件,减少电路板空间和材料成本。凭借12位差分ADC等先进模拟特性,AVR DA系列MCU可在嘈杂环境中测量小幅度信号,非常适合于哈希环境中的传感器节点应用。

AVR DA系列MCU的高存储密度和SRAM与闪存的比率使AVR DA系列产品对无线和有线连接的传感器节点以及其他协议栈密集型应用都具有吸引力。

开发工具

Microchip AVR DA系列提供多种软硬件支持选项。软件支持包括Microchip MPLAB® X、MPLAB Xpress和Atmel Studio,代码配置工具包括MCC和START,编译器包括GCC、XC8和IAR嵌入式工作台(IAR Embedded Workbench)。XC8编译器的功能安全认证版本可通过Microchip功能安全程序获得。硬件支持包含在调试器/编程器中,包括MPLAB PICkit™ 4、MPLAB SNAP、Atmel ICE和AVR128DA48 Curiosity Nano评估工具包。

供货与定价

AVR DA系列单片机现已实现量产,10,000枚起售,单价为0.87美元。如需了解更多信息,请联系Microchip销售代表、全球授权分销商或访问Microchip网站。如需购买上述产品,请访问“Microchip直销网站”或联系Microchip授权分销商。

资源

可通过Flickr或联系编辑获取高分辨率图片(可免费发布):
应用图:
https://www.flickr.com/photos/microchiptechnology/49584374872
模块图标:https://www.flickr.com/photos/microchiptechnology/49584047206

Microchip Technology Inc. 简介

Microchip Technology Inc.是致力于智能、互联和安全的嵌入式控制解决方案的领先供应商。 其易于使用的开发工具和丰富的产品组合让客户能够创建最佳设计,从而在降低风险的同时减少系统总成本,缩短上市时间。Microchip的解决方案为工业、汽车、消费、航天和国防、通信以及计算市场中12万多家客户提供服务。Microchip总部位于美国亚利桑那州Chandler市,提供出色的技术支持、可靠的产品交付和卓越的质量。详情请访问公司网站www.microchip.com

围观 11

单片机应用系统中,常有用单片机的I/O口来实现自关机(彻底关机)的功能。一般用单片机的一个I/O口控制一个电子开关来实现,因单片机关电后,失去电源,所以在关机时,实现关机的IO口的电平必须用低电平。

但在这里有一个矛盾,就是在电子开关关闭电源时,因有电源滤波电容的存在,单片机系统的电压不是立即变为0,而是慢慢变低,当电压低到一定电压时,单片机 将进入复位状态、或程序跑飞状态、或不确定状态,此时单片机控制关电的I/O口也可能变回高电平,将使电子开关重新开通。

解决方法:

一般单片机最低工作电压要比正常工作的电压低一些,我们就用这个差别来设计关机电路,就是让电子开关的开通电压必须大于单片机的最低工作压,这样在单片机正常工作时,此控制电压较高,能维持电子开关的正常导通,而当单片机在关电过程中因低压而产生的I/O口的高电平,因电压较低,不足以维持电子开关的导通, 从而实现彻底的关电。


在关机状态时:

S1按下,Q2导通,单片机工作后,POWER输出高电平,Q1导通,维持Q2的导通实现开机。

在开机状态时:

1、软件关机:MCU的POWER引脚输出低电平,Q1截止,Q2关断,关机。(一般用于延时关机,象数字万用表即是)

2、S1按下,低电平通过D3使MCU的输入脚ON-OFF电平为低,MCU检测到后,通过软件关机(如1所述)

D3用于隔离,不然关机状态时MCU的ON-OFF脚为低电平,Q2将导通。

POWER 是单片机输出开关电源的,低电平是0,高电平等于单片机的供电电压(近似)

ON-OFF是单片机的输入脚,用于单片机检测S1的状态,如果不用S1关机ON-OFF脚可以不用。

来源:网络,转载此文目的在于传递更多信息,版权归原作者所有。

围观 82

页面

订阅 RSS - 单片机