单片机与嵌入式区别.docx
《单片机与嵌入式区别.docx》由会员分享,可在线阅读,更多相关《单片机与嵌入式区别.docx(13页珍藏版)》请在冰豆网上搜索。
单片机与嵌入式区别
单片机和嵌入式系统linux的区别
随着嵌入式行业硬件平台的性能增强,项目需求和功能日益复杂,ARM公司推出的CORTEX-M3,更是让以往做单片机的工程师在芯片和技术选型面临两难选择,本专题将从芯片价格、整个系统的硬件软件设计及维护的成本等各个方面给您提供一个参考,并从技术角度分析单片机和带操作系统的系统的软件开发的异同点。
● 1.单片机与ARM等新处理器的价格比较
● 2.带操作系统与不带操作系统的软件开发的区别
● 2.1.驱动开发的区别
● 2.2.应用程序开发的区别
1.单片机与ARM等新处理器的价格比较
表1
型号
架构
资源
价格(元)
AT89S51
8051
最高频率33MHz
4KBFlash
128B内部RAM
32个可编程IO引脚
两个16bit的计数器
一个UART口
4
SST89E564RD
8051
最高频率40MHz
64KBFlash
1KB内部RAM
32个可编程IO引脚
三个16bit的计数器
一个UART口
一个SPI接口
35
STM32F103
CORTEX-M3
最高频率72MHz
64KB或128BKFlash
20KBSRAM
80个可编程IO引脚
2个12bit的ADC
7通道DMA控制器
标准调试口(SWD和JTAG)
7个定时器
USB接口
2个I2C接口
3个UART
2个SPI接口
21
HI3510
ARM9+DSP双核
最高工作频率240MHz
视频处理单元,支持多种协议的实时编解码
图形处理单元
视音频接口
以太网接口
DDR控制器
USB、UART、IrDA、
I2C、SPI、GPIO等多种外设接口
80
S3C2440
ARM9
最高工作频率400MHz
SDRAM控制器
LCD控制器
4通道DMA控制器
3个UART
2个SPI
1个I2C接口
IIS音频接口
SDHOST接口
2个USB接口
8个10bitADC
摄像头接口
Camera接口
40
从表1里面各种芯片的资源,大概就可以猜知它们的应用场合。
51单片机通常被用来做一些比较简单的控制,比如采集信号、驱动一些开关。
AT89S51的Flash只有4K,一个稍微复杂的程序就不止4K了。
SST89E564RD是一种扩展的51单片机,它的Flash达到64KB,可以外接最多64KB的SRAM。
在SST89E564RD上的程序可以写得更复杂一些,但是它对外的接口也比较少。
CORTEX-M3系列的处理器,对外接口极其丰富,这使得它的应用面更广,但是限于它的Flash、内存还是比较小,一般不在上面运行操作系统,它算是一个性能非常突出的单片机。
HI3510是海思半导体公司的一款用于监控设备的芯片,一般上面运行Linux系统,通过摄像头采集数据、编码,然后通过网络传输。
另一端接收到数据之后,再解码。
在上面运行的程序非常复杂,有漂亮的图片界面、触摸屏控制、数据库等等。
对声音图像的编解码更是用到DSP核。
S3C2440是一款通用的芯片,它与“高级单片机”STM32F103相比,多了存储控制器和NAND控制器──这使得可以外接更大的Flash、更大的内存;多了内存管理单元(MMU)──这使得它可以进行地址映身(虚拟地址、物理地址之间的映射)。
可以在S3C2440上运行Linux系统,运行更大更复杂的程序。
在具体工作中,怎么选择这些芯片呢?
一句话:
成本!
进行任何产品的开发都要考虑性价比,一切应该从“成本”出发。
成本不仅包括芯片的价格,也包括整个系统的硬件、软件设计及维护的难易。
芯片价格可以在电子市场问到,也可以在上找到有卖这种芯片的柜台,然后电话咨询。
基于不同的应用,处理器和其他外设的选择是要统一考虑的,如果要实现一个简单的U盘读写功能,那么可以选择带USB控制器的CORTEX-M3芯片,也可以选择8051外接一个USB控制器比如SL811,就看哪种方案成本更低。
进行芯片选型时,必须基于整个系统来考虑。
员工的偏好和知识结构也是一个很重要的因素,如果他对ATMEL的芯片比较熟,他就不会倾向于三星;如果他不会Linux等操作系统,那么选型时就不会有操作系统的概念。
选择自己不熟悉的芯片和技术,最后的成本也可能更高。
2.带操作系统与不带操作系统的软件开发的区别
用通俗的话来说,一个处理芯片不运行操作系统,我们就把它称为单片机,而单片机编程就是写裸板程序,这个程序直接在板子上运行;相对的,另一种程序就是基于操作系统的程序,说得简单点就是,这种程序可以通过统一的接口调用“别人写好的代码”,在“别人的基础上”更快更方便地实现自己的功能。
2.1.驱动开发的区别
驱动开发的区别我总结有两点:
能否借用、是否通用。
2.1.1能否借用
基于操作系统的软件资源非常丰富,你要写一个Linux设备驱动时,首先在网上找找,如果有直接拿来用;其次是找到类似的,在它的基础上进行修改;如果实在没有,就要研究设备手册,从零写起。
而不带操作系统的驱动开发,一开始就要深入了解设备手册,从零开始为它构造运行环境,实现各种函数以供应用程序使用。
举个例子,要驱动一块LCD,在单片机上的做法是:
①首先要了解LCD的规格,弄清楚怎么设置各个寄存器,比如设置LCD的时钟、分辨率、象素
②划出一块内存给LCD使用
③编写一个函数,实现在指定坐标描点。
比如根据x、y坐标在这块内存里找到这个象素对应的小区域,填入数据。
基于操作系统时,我们首先是找到类似的驱动,弄清楚驱动结构,找到要修改的地方进行修改。
下面是单片机操作LCD的代码:
①初始化:
voidTft_Lcd_Init(inttype)
{
/*
*设置LCD控制器的控制寄存器LCDCON1~5
*1.LCDCON1:
*设置VCLK的频率:
VCLK(Hz)=HCLK/[(CLKVAL+1)x2]
*选择LCD类型:
TFTLCD
*设置显示模式:
16BPP
*先禁止LCD信号输出
*2.LCDCON2/3/4:
*设置控制信号的时间参数
*设置分辨率,即行数及列数
*现在,可以根据公式计算出显示器的频率:
*当HCLK=100MHz时,
*Rate=1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x
* {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x
* {2x(CLKVAL+1)/(HCLK)}]
* =60Hz
*3.LCDCON5:
* 设置显示模式为16BPP时的数据格式:
5:
6:
5
* 设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号):
反转
* 半字(2字节)交换使能
*/
LCDCON1=(CLKVAL_TFT_320240<<8)|(LCDTYPE_TFT<<5)|\
(BPPMODE_16BPP<<1)|(ENVID_DISABLE<<0);
LCDCON2=(VBPD_320240<<24)|(LINEVAL_TFT_320240<<14)|\
(VFPD_320240<<6)|(VSPW_320240);
LCDCON3=(HBPD_320240<<19)|(HOZVAL_TFT_320240<<8)|(HFPD_320240);
LCDCON4=HSPW_320240;
// LCDCON5=(FORMAT8BPP_565<<11)|(HSYNC_INV<<9)|(VSYNC_INV<<8)|\
// (HWSWP<<1);
LCDCON5=(FORMAT8BPP_565<<11)|(HSYNC_INV<<9)|(VSYNC_INV<<8)|(VDEN_INV<<6)|\
(HWSWP<<0);
/*
*设置LCD控制器的地址寄存器LCDSADDR1~3
*帧内存与视口(viewpoint)完全吻合,
*图像数据格式如下:
* |----PAGEWIDTH----|
* y/x 0 1 2 239
* 0 rgbrgbrgb...rgb
* 1 rgbrgbrgb...rgb
*1.LCDSADDR1:
* 设置LCDBANK、LCDBASEU
*2.LCDSADDR2:
* 设置LCDBASEL:
帧缓冲区的结束地址A[21:
1]
*3.LCDSADDR3:
* OFFSIZE等于0,PAGEWIDTH等于(240*2/2)
*/
LCDSADDR1=((LCDBUFFER>>22)<<21)|LOWER21BITS(LCDBUFFER>>1);
LCDSADDR2=LOWER21BITS((LCDBUFFER+\
(LINEVAL_TFT_320240+1)*(HOZVAL_TFT_320240+1)*2)>>1);
LCDSADDR3=(0<<11)|(LCD_XSIZE_TFT_320240*2/2);
/*禁止临时调色板寄存器*/
TPAL=0;
fb_base_addr=LCDBUFFER;
bpp=16;
xsize=320;
ysize=240;
}
②描点:
/*
*画点
*输入参数:
* x、y:
象素坐标
* color:
颜色值
* 对于16BPP:
color的格式为0xAARRGGBB(AA=透明度),
* 需要转换为5:
6:
5格式
* 对于8BPP:
color为调色板中的索引值,
* 其颜色取决于调色板中的数值
*/
voidPutPixel(UINT32x,UINT32y,UINT32color)
{
UINT8red,green,blue;
switch(bpp){
case16:
{
UINT16*addr=(UINT16*)fb_base_addr+(y*xsize+x);
red=(color>>19)&0x1f;
green=(color>>10)&0x3f;
blue=(color>>3)&0x1f;
color=(red<<11)|(green<<5)|blue;//格式5:
6:
5
*addr=(UINT16)color;
break;
}
case8:
{
UINT8*addr=(UINT8*)fb_base_addr+(y*xsize+x);
*addr=(UINT8)color;
break;
}
default:
break;
}
}
下面是在Linux的LCD驱动里修改的地方(arch\arm\mach-s3c2440\mach-smdk2440.c):
/*320x240*/
staticstructs3c2410fb_mach_infosmdk2440_lcd_cfg__initdata={
.regs={
.lcdcon1=S3C2410_LCDCON1_TFT16BPP|\
S3C2410_LCDCON1_TFT|\
S3C2410_LCDCON1_CLKVAL(0x04),
.lcdcon2=S3C2410_LCDCON2_VBPD
(1)|\
S3C2410_LCDCON2_LINEVAL(239)|\
S3C2410_LCDCON2_VFPD(5)|\
S3C2410_LCDCON2_VSPW
(1),
.lcdcon3=S3C2410_LCDCON3_HBPD(36)|\
S3C2410_LCDCON3_HOZVAL(319)|\
S3C2410_LCDCON3_HFPD(19),
.lcdcon4=S3C2410_LCDCON4_MVAL(13)|\
S3C2410_LCDCON4_HSPW(5),
.lcdcon5=S3C2410_LCDCON5_FRM565|
S3C2410_LCDCON5_INVVLINE|
S3C2410_LCDCON5_INVV|
S3C2410_LCDCON5_INVVDEN|
S3C2410_LCDCON5_PWREN|
S3C2410_LCDCON5_HWSWP,
},
.gpccon=0xaaaa56aa,
.gpccon_mask=0xffffffff,
.gpcup=0xffffffff,
.gpcup_mask=0xffffffff,
.gpdcon=0xaaaaaaaa,
.gpdcon_mask=0xffffffff,
.gpdup=0xffffffff,
.gpdup_mask=0xffffffff,
.fixed_syncs=1,
.type=S3C2410_LCDCON1_TFT,
.width=320,
.height=240,
.xres={
.min=320,
.max=320,
.defval=320,
},
.yres={
.max=240,
.min=240,
.defval=240,
},
.bpp={
.min=16,
.max=16,
.defval=16,
},
};
这并不表示代码Linux的驱动程序就比单片机的驱动程序好写,怎么在几万个文件中找到要修改的代码,这也是需要艰苦的学习的。
基于操作系统的驱动开发,既要懂得芯片的具体操作,也要理解操作系统的软件结构。
2.1.2是否通用
有些单片机厂家也给客户提供了大量的驱动程序,比如USBHOST驱动程序,这可以让客户很容易就可以在它的上面编写程序读写U盘。
但是客户写的这些程序,只能在这种芯片、这个驱动程序上使用;更换另一种芯片后,即使芯片公司也提供了驱动程序,但是接口绝对不一样,客户又得重新编写应用程序。
基于操作系统的驱动程序要遵循统一的接口,比如对于不同的芯片的USBHOST驱动,它们都要向上提供一个相同的数据结构,在里面实现了各自的USB操作。
下面是S3C2410/S3C2440的USB驱动向上层提供的数据结构:
staticconststructhc_driverohci_s3c2410_hc_driver={
.deion=hcd_name,
.product_desc="S3C24XXOHCI",
.hcd_priv_size=sizeof(structohci_hcd),
/*
*generichardwarelinkage
*/
.irq=ohci_irq,
.flags=HCD_USB11|HCD_MEMORY,
/*
*basiclifecycleoperations
*/
.start=ohci_s3c2410_start,
.stop=ohci_stop,
.shutdown=ohci_shutdown,
/*
*managingi/orequestsandassociateddeviceresources
*/
.urb_enqueue=ohci_urb_enqueue,
.urb_dequeue=ohci_urb_dequeue,
.endpoint_disable=ohci_endpoint_disable,
/*