产品选型

单片机arm入门 入门ARM,何必买书籍学课程,看这一篇就够了

小编 2024-10-24 产品选型 23 0

入门ARM,何必买书籍学课程,看这一篇就够了

消失的飞思卡尔:MKV30 16位AD采集

16位的AD可以说是国产MCU的痛点,至少在廉价的单片机里面,这个真的找不到飞思卡尔的替代品。之前未使用16位AD的时候,使用的是STM32F0的单片机,因为产品需要,一直是将48M的主频超频到56M跑超速,后来因为疫情等原因,ST的价格飞上天,交期还特长,无奈之下换了国产兆易创新的GD32,不得不说,对标的GDE23主频直接到了72M,M0+,不用超频,正常跑高速就行。价格还便宜,不收过路费。在这一点上,国产的MCU真的很强。

现在项目需要16位的AD,一时间找不到任何国产的替代品,当然我们也把主意打到了ST的头上,但是捋到STM32H7才找到16位AD,2020年的ST的价格大家都清楚,如果选用这款芯片,我们的产品成本将大大增加,这已经超出了我们的预算。在之后的一番寻找中,确定了这个被恩智浦收购了多年的飞思卡尔的芯片。MKV30,价格便宜,针对电机行业出生的MCU,在ADC的处理上可谓是下足了功夫。

自带差分输入模块,支持高达16位的差分AD输入,

自带硬件平均,可对输入的AD信号进行自动平均,

支持低功耗和高速AD模式,可自动校准AD,

自带比较器。

但是,因为很早就被收购,所以飞思卡尔的资料并不如NXP自家的产品那样详细丰富,导致开发难度很大,而且这款芯片不像K60那款,因为早期有智能车竞赛的缘故,网友分享的资料和经验很多。这款我拿到手里就很懵。本人并不是大佬,对新的单片机上手不是很容易。在开发的第一周就点了个灯,到处是坑。

下面分享我的开发过程和经验:

官网下载SDK直接pass,在有个基础工程的基础上使用MCUXpresso Config Tool配置ADC的引脚和功能初始化。

配置引脚:

因为我需要使用两路ADC的差分模式,这里配置ADC0和ADC1的引脚。使用PORTE16、PORTE17 、PORTE18 、PORTE19四个引脚。对应ADC的ADC0_DP1,ADC0_DM1,ADC1_DP1,ADC1_DM1。软件会自动配置引脚相关配置代码。

ADC配置:

配置为16位的差分AD,因为我追求最高速的ADC采集,所以时钟1分频,硬件的8次平均。

ADC1配置相同。

开始进入代码:

/*******************************************************************************

* Definitions

******************************************************************************/

#define DEMO_ADC16_CHANNEL 1U

#define DEMO_ADC16_CHANNEL_GROUP 0U

#define DEMO_ADC16_BASEADDR ADC0

#define DEMO_DMAMUX_BASEADDR DMAMUX0

#define DEMO_DMA_CHANNEL 1U

#define DEMO_DMA_ADC0_SOURCE 40U

#define DEMO_DMA_ADC1_SOURCE 41U

#define DEMO_DMA_BASEADDR DMA0

#define ADC16_RESULT_REG_ADDR 0x4003b010U

#define ADC16_RESULT_REG_ADDR1 0x40027010U//查询寄存器手册得到

#define DEMO_DMA_IRQ_ID DMA0_IRQn

#define DEMO_ADC16_SAMPLE_COUNT 8U /* The ADC16 sample count. */

/***********************************************************************************************************************

* ADC0 initialization code

**********************************************************************************************************************/

adc16_channel_config_t ADC0_channelsConfig[1] = {

{

.channelNumber = 1U, //传输通道

.enableDifferentialConversion = true, //差分模式

.enableInterruptOnConversionCompleted = false, //使能传输完成中断

}

};

const adc16_config_t ADC0_config = {

.referenceVoltageSource = kADC16_ReferenceVoltageSourceVref,

.clockSource = 0,

.enableAsynchronousClock = false,

.clockDivider = kADC16_ClockDivider1,

.resolution = kADC16_ResolutionSE16Bit,

.longSampleMode = kADC16_LongSampleDisabled,

.enableHighSpeed = true,

.enableLowPower = false,

.enableContinuousConversion = false//连续的转换

};

const adc16_channel_mux_mode_t ADC0_muxMode = kADC16_ChannelMuxA;

/* 硬件平均 8 */

const adc16_hardware_average_mode_t ADC0_hardwareAverageMode = kADC16_HardwareAverageDisabled;

void ADC0_init(void) {

/* Initialize ADC16 converter */

ADC16_Init(ADC0_PERIPHERAL, &ADC0_config);

/* Make sure, that software trigger is used */

ADC16_EnableHardwareTrigger(ADC0_PERIPHERAL, false);

/* Configure hardware average mode */

ADC16_SetHardwareAverage(ADC0_PERIPHERAL, ADC0_hardwareAverageMode);

/* Configure channel multiplexing mode */

ADC16_SetChannelMuxMode(ADC0_PERIPHERAL, ADC0_muxMode);

/* Initialize channel */

ADC16_SetChannelConfig(ADC0_PERIPHERAL, 0U, &ADC0_channelsConfig[0]);

/* Perform auto calibration */

ADC16_DoAutoCalibration(ADC0_PERIPHERAL);

/* Enable DMA. */

ADC16_EnableDMA(ADC0_PERIPHERAL, false);

}

/***********************************************************************************************************************

* ADC1 initialization code

**********************************************************************************************************************/

adc16_channel_config_t ADC1_channelsConfig[1] = {

{

.channelNumber = 2U,

.enableDifferentialConversion = true, //差分模式

.enableInterruptOnConversionCompleted = false,

}

};

const adc16_config_t ADC1_config = {

.referenceVoltageSource = kADC16_ReferenceVoltageSourceVref,

.clockSource = 0,

.enableAsynchronousClock = false,

.clockDivider = kADC16_ClockDivider1,

.resolution = kADC16_ResolutionSE16Bit,

.longSampleMode = kADC16_LongSampleDisabled,

.enableHighSpeed = true,

.enableLowPower = false,

.enableContinuousConversion = false//连续的转换

};

const adc16_channel_mux_mode_t ADC1_muxMode = kADC16_ChannelMuxA;

const adc16_hardware_average_mode_t ADC1_hardwareAverageMode = kADC16_HardwareAverageDisabled;

void ADC1_init(void) {

// EnableIRQ(ADC0_IRQn);

/* 初始化ADC16转换器 */

ADC16_Init(ADC1_PERIPHERAL, &ADC1_config);

/* 不使用软件触发器 */

ADC16_EnableHardwareTrigger(ADC1_PERIPHERAL, false);

/* 配置硬件平均模式 */

ADC16_SetHardwareAverage(ADC1_PERIPHERAL, ADC1_hardwareAverageMode);

/* 配置信道多路复用模式 */

ADC16_SetChannelMuxMode(ADC1_PERIPHERAL, ADC1_muxMode);

/* 初始化通道 */

ADC16_SetChannelConfig(ADC1_PERIPHERAL, 1U, &ADC1_channelsConfig[0]);

/* 自动校准 */

ADC16_DoAutoCalibration(ADC1_PERIPHERAL);

/* Enable DMA. */

ADC16_EnableDMA(ADC1_PERIPHERAL, false);

}

这里以ADC0为例,传输通道设置为1,配置为差分模式,不使能传输完成中断。ADC0_config结构体中的配置主要是配置时钟和采样速度,我的配置是我能达到的最高速度。在ADC0_init函数中,配置为软件触发,如果使用PDB,需要改为硬件触发,关闭了硬件平均。

当我们需要获取ADC的数据时,需要以下代码。

adc16_channel_config_t adc16ChannelConfigStruct;

adc16ChannelConfigStruct.channelNumber = 1; //ADC通道

adc16ChannelConfigStruct.channelNumber = 2;

adc16ChannelConfigStruct.enableDifferentialConversion = true;//使能差分

adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false;//失能中断

ADC16_SetChannelConfig(ADC1, 0U, &adc16ChannelConfigStruct);

ADC16_SetChannelConfig(ADC0, 0U, &adc16ChannelConfigStruct);

while (0U == (kADC16_ChannelConversionDoneFlag &

ADC16_GetChannelStatusFlags(ADC1, 0U)));

ADC_Value0 = ADC16_GetChannelConversionValue(ADC0, 0U);

ADC_Value1 = ADC16_GetChannelConversionValue(ADC1, 0U);

可以将上述代码添加进主循环,在需要AD值时便可以直接读取ADC_Value0和ADC_Value1的值便可,可以包装成一个函数,需要时调用即可,执行一次该代码大约需要3us。如果AD的通道很多,可以使用for循环,改善代码。但是此方法占用MCU的内存,下一篇更新灵活多通道的DMA采集。

要点:

这里配置为ADC16位模式,但是并不是真正意义上的16位,在数据寄存器中有介绍,数据寄存器是16位,只有第15位是有效数据位,最高位为16位,所以ADC的范围是0~32767,加上最高位的符号位能达到-32767~+32767.

我在这里没看手册,采集到的数据一直无法理解。

输入通道输入的是正弦波,结果串口打印出来的确是这个玩意,最后处理一下符号位解决。

上电之后会开始ADC采集,ADC采集完成触发dma通道1开始传输到指定缓存,dma通道1传输完成触发链接,链接dma通道2,dma通道2将adc配置传给adc配置寄存器。这样可以灵活采集各种通道,并且对资源占用较小。只要设置好配置adc的数组,剩下的dma就会处理.DMA配置: void EDMA_Configuration(void){ edma_config_t userConfig; /* 配置 DMAMUX */ DMAMUX_Init(DMAMUX); /* 通道CH1初始化 */ DMAMUX_SetSource(DMAMUX, 1, 40); /* Map ADC0 source to channel 1 */ DMAMUX_EnableChannel(DMAMUX, 1); /* 通道CH2初始化 */ DMAMUX_SetSource(DMAMUX, 2, 41);/* Map ADC1 source to channel 2 */ DMAMUX_EnableChannel(DMAMUX, 2); /* 获取eDMA默认配置结构 */ EDMA_GetDefaultConfig(&userConfig); EDMA_Init(DMA0, &userConfig); EDMA_CreateHandle(&g_EDMA_Handle, DMA0, 1); /* 设置回调 */ EDMA_SetCallback(&g_EDMA_Handle, Edma_Callback, NULL); /*eDMA传输结构配置 .设置dma通道1的adc值传到g_adc16SampleDataArray*/ EDMA_PrepareTransfer(&transferConfig, (void *)ADC16_RESULT_REG_ADDR, sizeof(uint32_t), (void *)g_adc16SampleDataArray, sizeof(uint32_t), sizeof(uint32_t), sizeof(g_adc16SampleDataArray), kEDMA_PeripheralToMemory); EDMA_SubmitTransfer(&g_EDMA_Handle, &transferConfig); /* Enable interrupt when transfer is done. */ EDMA_EnableChannelInterrupts(DEMO_DMA_BASEADDR, DEMO_DMA_CHANNEL, kEDMA_MajorInterruptEnable);#if defined(FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT) && FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT /* Enable async DMA request. */ EDMA_EnableAsyncRequest(DEMO_DMA_BASEADDR, DEMO_DMA_CHANNEL, true);#endif /* FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT */ /* Enable transfer. */ EDMA_StartTransfer(&g_EDMA_Handle); //将dma通道1链接到通道0 EDMA_SetChannelLink(DMA0, 1, kEDMA_MinorLink, 2); EDMA_SetChannelLink(DMA0, 1, kEDMA_MajorLink,2);//*********************************************************************************************/ EDMA_CreateHandle(&DMA_CH2_Handle, DMA0, 2); EDMA_SetCallback(&DMA_CH2_Handle, Edma_Callback1, NULL); /* 设置回调 */ EDMA_PrepareTransfer(&g_transferConfig, (void *)ADC16_RESULT_REG_ADDR1, sizeof(uint32_t), (void *)g_adc16SampleDataArray1, sizeof(uint32_t), sizeof(uint32_t), sizeof(g_adc16SampleDataArray1), kEDMA_PeripheralToMemory); EDMA_SubmitTransfer(&DMA_CH2_Handle, &g_transferConfig); //传输完后修正通道 DMA0->TCD[1].DLAST_SGA = -1* sizeof(g_adc16SampleDataArray); DMA0->TCD[2].DLAST_SGA = -1* sizeof(g_adc16SampleDataArray1); /* 当传输完成时启用中断. */ EDMA_EnableChannelInterrupts(DEMO_DMA_BASEADDR, 2, kEDMA_MajorInterruptEnable);#if defined(FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT) && FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT// /* 启用异步DMA请求 */ EDMA_EnableAsyncRequest(DEMO_DMA_BASEADDR, 2, true);#endif /* FSL_FEATURE_EDMA_ASYNCHRO_REQUEST_CHANNEL_COUNT */ /* 使能数据传输 */ EDMA_StartTransfer(&DMA_CH2_Handle); }DAM 通道1和通道2的callback函数。 因为通道2是通过通道一链接触发的,所以在通道1的回调函数里面就不用再调用EDMA_StartTransfer()函数了。 此处注意将ADC的采样模式改为连续模式。 static void Edma_Callback(edma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds){ EDMA_StartTransfer(&g_EDMA_Handle); g_Transfer_Done = false; if (transferDone) { g_Transfer_Done = true; }}static void Edma_Callback1(edma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds){ g_Transfer_Done1 = false; if (transferDone) { g_Transfer_Done1 = true; }}至此ADC的DMA就完成了,ADC会一直采集并通过DMA传输到g_adc16SampleDataArray[]和g_adc16SampleDataArray1[]两个数组中,需要时可以直接取值。我在使用ADC的DMA连续采样时遇到一个问题,因为连续采样会触发callback函数,此过程会触发edma中断,容易打断原来代码的进程,如在高速应用中使用需注意。

原标题:消失的飞思卡尔:MKV30 16位AD采集

原作者:呐咯密密

本文为21ic有奖征文作品,详情请见21ic论坛活动专区:第一届万元红包——蓝V达人有奖征文活动,如果您也有兴趣参与征文,欢迎进入论坛参与活动~

从单片机转ARM,ARM架构基础知识小结

从单片机转到ARM,主要需要学习ARM的架构,ARM相比单片机多了一些外设和总线。在仅仅是裸奔的情况下,如果熟悉了ARM架构,那么我认为使用任何ARM架构的芯片和用单片机将没有区别。ARM架构之所以更复杂,当然是为了跑更快以及更好地支持片上系统,所以在某种程度上来说对片上系统不是很了解的话那对于ARM架构的理解也不会那么深。

通用寄存器

R13通常被用作栈指针,进入异常模式时,可以将需要使用的寄存器保存在R13所指的栈中;当退出异常吹程序时,将保存在R13所指的栈中的寄存器值弹出。

R14又被称为连接寄存器(LinkRegister,LR),即PC的返回值。

R15又被记作PC。ARM指令是字对齐的,PC的值的第0位和第1位总为0。也就是说是32位对齐。

就Cortex-M3来说,拥有R0-R15的寄存器组。其中R13作为堆栈指针SP。SP有两个,分别为R13(MSP)和R13(PSP)即主堆栈指针(MSP)和进程堆栈指针(PSP),但在同一时刻只能有一个可以看到,这也就是所谓的“banked”寄存器。这些寄存器都是32位的。

ARM的各个模式

ARM有以下7种模式:

用户模式(User,usr) 正常程序执行的模式

快速中断模式(FIQ,fiq) 用于高速数据传输和通道处理

外部中断模式(IRQ,irq) 用于通常的中断处理

特权模式(Supervisor,svc) 供操作系统使用的一种保护模式

数据访问中止模式(Abort,abt) 用于虚拟存储及存储保护

未定义指令中止模式(Undefined,und) 用于支持通过软件方针硬件的协处理器

系统模式(System,sys) 用于运行特权级的操作系统任务

其中除了用户模式之外都称之为特权模式(privileged modes),而在privileged modes中除了系统模式其它都称为异常模式,即exception mode。起初关于异常这个词我的理解有些偏差,我认为异常模式就是这个系统出错了,而实际上不是。exception mode的意思是例外,意思是“这模式什么时候会发生不好说……”,比如说来了个外部中断也会进入异常模式,但是此时系统是运行完好的。

其中SVC用于在系统刚启动的启动文件BOOT程序中,跳转到kernel之前必须为SVC,SVC具有最高权限,可以对任何寄存器进行操作。在裸机程序中我们有时候会一直处于SVC模式下。

关于什么时候会进入用户模式或者系统模式,以下是我的猜测,比如进入linux kernel之后会设置成sys模式,比如任务调度等等都会在sys模式中,而执行用户编写的应用程序时,系统是处于usr模式中。以上猜测需要在linux中找出证据验证。

其中FIQ,IRQ为中断模式,有中断发生时会进入FIQ模式或者IRQ模式,至于到底是进入哪个模式是由开发者设定的。理论上FIQ模式的响应速度比IRQ模式要快。

其中abt模式通常发生于在访问地址没有对齐时的情况,此时会跳转到abt所属的中断向量地址中去。und模式应该是取到指令之后发现指令不能用,,此时会跳转到abt所属的中断向量地址中去。以上两种模式应该是开发过程中出现BUG才会进入的,也是一种调试手段,在版本发行之前应该消除这些错误(我猜= =)。

启动文件

这一部分只要了解一下协处理器CP15的相关作用以及ARM或者THUMB汇编再看一下网上的例程以及解释应该不难理解。

在启动文件中我们可以做任何事情,但是通常我们可以做这些:改变程序大小端排序,关闭看门狗,屏蔽中断,设置各个时钟,设置从SLEEP或者IDLE启动时的程序,初始化SDRAM,设置各模式指向的堆栈,设置好中断向量表,判断是从NOR还是NAND FLASH启动,将文件拷到SDRAM中,运行Main。

以上也说明了为什么需要一个汇编写的启动文件,设置各个模式下的SP指针以及初始化中断向量的跳转(ARM的中断较多设置也较灵活)也只有汇编干比较合适了。甚至在SOC(片上系统)中每个任务都有自己的堆栈,所以改变堆栈指针的那一部分程序也是放在汇编里做的。总之了解启动文件是一个非常好的切入点。

MMU相关地址基本概念

关于MMU,因为多种存储设备的物理地址不同以及不连贯性,将其地址安放在合理的连续虚拟地址上是很必要的,所以MMU出现了。MMU即将不同的地址放在合适的虚拟地址中,以便调度。比如要跑LINUX必须要有MMU的支持才行。

ARM920T中有三种类型的地址:

虚拟地址(VA),变换后的虚拟地址(MVA),物理地址(PA)。

以下是一个当一个指令被请求时地址所做操作的例子:

1、 指令VA(IVA)被ARM920T发出

2、 它被ProcID(当前进程所在的进程空间块的编号)转换成指令MVA(IMVA),指令CACHE(ICACHE)和MMU看到的就是IMVA。

3、 如果在IMMU上的保护模块确认IMVA不会被中断,并且IMVA标签也在ICACHE中,指令数据会读出并返回到ARM920T内核中。

4、 如果IMVA tag并不在ICACHE中,那么IMMU会产生出一个指令PA(IPA)。地址会给AMBA总线接口以获取外部数据。

那么VA是如何被PID转换为MVA的呢?

这有关于CP15中的13,FCSE PID register

R13是fast context switch extension(FCSE 快速上下文切换扩展)processidentifier(PID 进程标识符)寄存器,此寄存器复位时为0。

读R13会得到FCSE PID的值,写R13会更新FCSE PID的值到[31:25]中,位[24:0]应该是零。

如何使用FCSE PID:

920T内核发出的地址都是0-32MB的范围,4GB的逆序空间被分成了1238个进程空间块,每个进程空间块大小为32MB。每个进程空间块中可以包含一个进程。系统128个进程空间块的编号0-127,编号为I的进程空间块中的进程实际使用的虚拟地址空间为(I*0x02000000)到(I*0x02000000+0x01FFFFFF)。

所以VA通常高7位都为0时 MVA = VA | (PID << 25)

当VA高7位不为0时 MVA = VA,这种VA是本进程用于访问别的进程中的数据和指令的虚拟地址,注意这时被访问的进程标识符不能为0。

注意:当FCSE_PID为0时,即当前复位,则当前920T和CACHES及MMU之间是平面映射的关系(很巧妙:))。

TLB是什么

TLB即translate look-aside buffer,快表就是存储几个常用的页表,以提高系统运行的速度。在更新页表之前要使其无效,其操作的寄存器为R8,R8为只写寄存器,如果读它则会造成不可估计的后果。

AP赋值表:

而DOMAIN的赋值则是在C3中的,32bit共有16个域,每个域分两个bit,这两个bit控制当前域的权限。而以上四个bit是为了选择0-15个域的其中一个。

关于C、B赋值:

以上有关于两种写缓存,写通以及写回。写回法是指CPU在执行写操作时,被写的数据只写入cache,不写入主存,仅当需要替换时,才把已经修改的cache块写回到主存中。写通法是指CPU在执行写操作时,必须把数据同时写入cache和主存。

时钟以及总线概念

FCLK, HCLK, andPCLK

FCLK is used byARM920T.

HCLK is used forAHB bus, which is used by the ARM920T, the memory controller, the interruptcontroller, the LCD controller, the DMA and USB host block.

PCLK is used forAPB bus, which is used by the peripherals such as WDT, IIS, I2C, PWM timer, MMCinterface,ADC, UART, GPIO, RTC and SPI.

What is AHB/APB?

InternalAdvanced Microcontroller Bus Architecture(AMBA)是一种总线标准,以下两项都符合此标准。

AHB(AdvancedHigh performance Bus),主要用于系统高性能、高时速速率模块间通信。

APB(AdvancedPeripheral Bus),主要用于慢速片上外设与ARM核的通讯。

AHB私有外设总线,只用于CM3内部的AHB外设,它们是:NVIC,FPB, DWT和ITM。

APB私有外设总线,既用于CM3内部的APB设备,也用于外部设备(这里的“外部”是对内核而言)。CM3允许器件制造商再添加一些片上APB外设到APB私有总线上,它们通过APB接口来访问。

四种耗电模式:

NORMAL,SLOW,IDLE,SLEEP

先配置主PLL MPLL给CPU用。在上电复位的时候PLL是不稳定的,所以在PLLCON在被软件配置之前Fin直接是跳过MPll给FCLK,所以不配置PLLCON也是可以正常工作。即使工作在正常状态下,也可以对MPLLCON进行配置,配置之后等待PLL Lock-time过后内部各模块的CLK才可以被正常供应。

相关问答

arm 如何 入门 ?需要哪些预备课程?

学什么都要有目的性,ARM也分多种,ARM7,ARM9,ARM11,CORTEX-M系列,CORTEX-A系列等等,学这个必须软件、硬件都要懂,看你偏重那一面,还有你是否需要跑操作系...学...

如果没有 单片机 基础,能直接学习 ARM 吗?参加 ARM 培训可以吗?

当然可以,事实上现在很多学校就不教单片机,只教ARM。呵呵呵,就跟现在的人不会学DOS直接学WINDOWS一样。当然可以,事实上现在很多学校就不教单片机,只教ARM。...

寒假期间想学下 单片机 ,有C语言的基础,怎么下手呢?

寒假即将来临,想在假期将近一个月中学习一项技能,我认为这是一个不错的想法。下面我给这位朋友提两个建议,希望能对所有想学单片机的初学者有所参考作用。我...

arm入门 应当学些什么,linux系统有什么用啊-ZOL问答

直接学arm的话可能有点难度,你可以先学学单片机,例如51系列,AVR。然后再逐渐过渡到ARM。arm是嵌入式开发应用的硬件,linux是嵌入式开发应用的软件。我们所谓...

想学习 ARM单片机 了,要先学什么我已经学了51单片机C语言模电数电接下来要学什么内容?

建议直接学ARM吧,单片机没有OS。ARM一般带OS。弄个开发板学习下,都有入门教程。。有老师带最好,不然就看你个人学习能力了建议直接学ARM吧,单片机没有OS。ARM...

学完 单片机 ,并且应用做过项目,想学 ARM ,linux应该走怎样的学习路线比较好?

...做Linux开发的工作有很多种,总结来说有偏上层应用的,也有偏驱动开发的。做上层应用就需要了解Linux系统不用了解太深,但是应用层的一些扩展要掌握,例如li...

51单片机与 ARM单片机 的区别有哪些?

ARM单片机全面占优。第一、ARM单片机处理速度块、处理才能强、贮存容量大、给用户带来便当。传统的51单片机为8为处理器,而ARM芯片为32位处理器,简略的说,51...

如何在ucos下进行 arm 编程?

如:arm920TE.pdfS3C2410_1.2.pdf6、学习uCOS!!操作系统。(1)、细读《嵌入式实时操作系统uC/OS-!!》第二版召贝贝译你能把uCOS!!移植到自己的...

arm 单片机 的关系?

ARM是英国Acorn有限公司设计的低功耗成本的第一款RISC微处理器。全称为AdvancedRISCMachine。ARM处理器本身是32位设计,但也配备16位指令集,一般来讲比等价3...

谁能教教我怎么学 单片机 ,先学什么,怎么 入门 ?

我可以,单片机入门简单。你有c语言基础吗?简单的电路基础吗?有的话51单片机,两个星期就可以做出蛮好的小东西。没有基础的话,先看看c语言,看到函数和数组...

猜你喜欢