历史上的今天
返回首页

历史上的今天

今天是:2024年12月17日(星期二)

正在发生

2018年12月17日 | ARM7系列LPC2214芯片的调试报告

2018-12-17 来源:eefocus

摘要:本文的主要内容是关于PHILIP公司ARM7系列LPC2214芯片的调试报告,以及在其基础上的网络通信程序设计的调试报告和KEIL公司的开源RTL操作系统下TCPNET不开源协议栈的工作报告;在具体论述我的调试过程的时候,我会把我查询的一些我认为正确的资料附在合适的位置,以供参考。


LPC2214启动代码部分


启动代码-汇编代码--做c语言的准备工作。包括向量表定义,堆栈初始化,系统变量初始化,中断系统初始化,i/o初始化,外围初始化,地址重映射等操作。


在开始之前我建议首先把ARM的指令系统熟悉一遍,然后结合启动代码熟悉指令的含义和具体操作,尤其需要的是要比较明确的知道startup.s文件中的伪指令的含义,这将给你以后堆栈的大小等带来一个概念;


基本结构


下面是关于启动文件一个说明,模仿于UV3软件提供PHILIP 的LPC2000系列芯片的startup文件;在说明之前你有必要先熟悉ARM指令集,注意他的模块化的结构;VPBDIV、PLL、


MAM、EMC、BCG0-3等的设置比较模式化,熟悉下datasheet说明后,比较容易设置好,


要留意的就是PINSEL0-2的设置,根据自己的外部接口配置PINSEL。


LPC2114启动代码的编写主要包括:


    1.异常向量表的建立  


    2.MCU各种模式堆栈的初始化


    3.系统基本的初始化工作


    下面分别进行介绍.


(一)ARM相关指令及伪指令


     LDR PC,ResetAddr


     将ResetAddr标号地址所指的内容传送给PC寄存器


     LDR PC,=ResetAddr


     将ResetAddr标号地址传送给PC寄存器


     ResetAddr DCD ResetInit


 为ResetAddr分配一个字的地址空间,以ResetInit初始化,即ResetAddr地址所指的内容为ResetInit标号地址


     SvcStackSpace Space SVC_STACK_LENGTH*4


 为SvcStackSpace分配一块SVC_STACK_LENGTH*4大小的地址区域,并以0初始化区域内容


(二)异常向量表的建立


 异常是有内部或外部源产生的,以引起处理器处理的一个事件,异常出现后,CPU强制从异常类型对应的固定存储地址开始执行程序,如当IRQ中断产生后,CPU强制跳转到0x00000018出执行代码,我们要做的就是在这个代码地址出编写相应的指令,让它顺利执行IRQ中断程序.通常我们会在这里放置一条转移指令,因为0x00000018只给你一个字的编程空间.


     程序如下:


AREA    vectors,CODE,READONLY


ENTRY


;interrupt vectors


;中断向量表


Reset


        LDR     PC, ResetAddr


        LDR     PC, UndefinedAddr


        LDR     PC, SWI_Addr


        LDR     PC, PrefetchAddr


        LDR     PC, DataAbortAddr


        DCD     0xb9205f80


        LDR     PC, [PC, #-0xff0]


        LDR     PC, FIQ_Addr


ResetAddr             DCD     ResetInit


UndefinedAddr       DCD     Undefined


SWI_Addr             DCD     SoftwareInterrupt


PrefetchAddr         DCD     PrefetchAbort


DataAbortAddr       DCD     DataAbort


Nouse                   DCD     0


IRQ_Addr             DCD     0


FIQ_Addr             DCD     FIQ_Handler


;未定义指令


Undefined


        B       Undefined


;软中断


SoftwareInterrupt   


        B       SoftwareInterrupt 


;取指令中止


PrefetchAbort


        B       PrefetchAbort


;取数据中止


DataAbort


        B       DataAbort


;快速中断


FIQ_Handler


        STMFD   SP!, {R0-R3, LR}


        BL      FIQ_Exception


        LDMFD   SP!, {R0-R3, LR}


        SUBS    PC,  LR,  #4


 IRQ_Addr            DCD     0


FIQ_Addr            DCD     FIQ_Handler


   **


        **


ResetInit


       


        BL      InitStack               ;初始化堆栈 Initialize the stack


        BL      TargetResetInit         ;目标板基本初始化 Initialize the target board


                                        ;跳转到c语言入口 Jump to the entry point of C program


        B       __main


        我们可以看到,每种异常都有相应的处理程序,如:当系统复位后,程序跳转到0x00000000处执行指令,那么就执行  LDR     PC, ResetAddr,及执行ResetInit地址处的代码,这里放置了BL     InitStack指令,负责完成各种模式下堆栈的初始化,接着执行BL      TargetResetInit ,完成目标板基本初始化,最后进入c语言入口,执行main函数.


(三)MCU各种模式堆栈的初始化


        由于各种异常模式下都有自身的SP堆栈指针,因此就必须先进入各自的异常模式进行SP的设置,各种模式的切换可以通过改变CPSR来实现,程序如下:


InitStack   


        MOV     R0, LR


;Build the SVC stack


;设置管理模式堆栈


        MSR     CPSR_c, #0xd3  


        LDR     SP, StackSvc 


;Build the IRQ stack 


;设置中断模式堆栈


        MSR     CPSR_c, #0xd2


        LDR     SP, StackIrq


;Build the FIQ stack


;设置快速中断模式堆栈


        MSR     CPSR_c, #0xd1


        LDR     SP, StackFiq


;Build the DATAABORT stack


;设置中止模式堆栈


        MSR     CPSR_c, #0xd7


        LDR     SP, StackAbt


;Build the UDF stack


;设置未定义模式堆栈


        MSR     CPSR_c, #0xdb


        LDR     SP, StackUnd


;Build the SYS stack


;设置系统模式堆栈


        MSR     CPSR_c, #0x5f


        LDR     SP, =StackUsr



        MOV     PC, R0


**


**


StackSvc           DCD     SvcStackSpace + (SVC_STACK_LEGTH - 1)* 4


StackIrq           DCD     IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4


StackFiq           DCD     FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4


StackAbt           DCD     AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4


StackUnd           DCD     UndtStackSpace + (UND_STACK_LEGTH - 1)* 4


**


**


;/* 分配堆栈空间 */


        AREA    MyStacks, DATA, NOINIT, ALIGN=2


SvcStackSpace      SPACE   SVC_STACK_LEGTH * 4  ;Stack spaces for Administration Mode 管理模式堆栈空间


IrqStackSpace      SPACE   IRQ_STACK_LEGTH * 4  ;Stack spaces for Interrupt ReQuest Mode 中断模式堆栈空间


FiqStackSpace      SPACE   FIQ_STACK_LEGTH * 4  ;Stack spaces for Fast


Interrupt reQuest Mode 快速中断模式堆栈空间


AbtStackSpace      SPACE   ABT_STACK_LEGTH * 4  ;Stack spaces for Suspend Mode 中止义模式堆栈空间


UndtStackSpace     SPACE   UND_STACK_LEGTH * 4  ;Stack spaces for Undefined Mode 未定义模式堆栈


****


***


 AREA    Stacks, DATA, NOINIT


StackUsr


说明:MSR     CPSR_c, #XX指令完成各种异常模式的切换,如切换到IRQ模式,则执行MSR     CPSR_c, #0xd2,而SP的值由SvcStackSpace的地址加上SVC_STACK_LEGTH 的所指的大小而定.


(四)系统基本的初始化工作


完成堆栈初始化后执行BL      TargetResetInit,它负责系统一些基本的初始化,如地址重映射,PLL时钟初始化,VIC中断初始化等,具体代码见Easy Arm系列开发版的target.c文件.


 最后,执行B       __main,__main是ADS的一个系统函数,它负责一些初始化环境然后执行用户的main函数.


REMAP概念


典型的Boot、Memory Map和Remap的时间顺序应该是:Memory Map-〉Boot-〉Remap。 但是,LPC2000处理器中这三个动作的顺序却有一点不同,依次为Memory Map-〉Remap-〉Boot-〉Remap,最后一个Remap过程是用户可选的,可执行也可不执行。每当系统复位以后,LPC2000处理器就顺次执行上述四个过程,下面分析这几个阶段。为简化起见,以总线不开放的LPC2104处理器为例。


LPC2106的片上存储器分类


LPC2104片内的存储器类型只有两种:Flash块和SRAM块。其中,部分Flash存储器块在芯片出厂前由Philips写入了Bootload程序和64字节的异常向量表。为方便讨论,我们称这部分Flash块为Bootload子块,其大小为8KB。如前所述,在处理器未上电之前或复位时,Flash块和SRAM块仅仅是两个没有地址编码的物理存储器,与地址编码尚未建立起实际的映射关系。


Memory Map


LPC2104处理器(上电)复位以后,Flash块和SRAM块的地址映射结果为:SRAM占据0x40000000—0x40003FFF范围的地址编码空间;Flash占据0x00000000—0x0001FFFF范围的地址编码空间。该映射结果是个中间态,只存在极短的时间,应用系统开发人员无法看到这个中间态。处理器内核外围模块的地址映射结果为0xE0000000—0xFFFFFFFF。


Memory Map完成以后,紧接着LPC2104会作一次Remap,这次Remap操作的对象是Bootload子块,由处理的内部硬件逻辑执行完成,不受开发人员的控制。经过Remap后,Bootload子块被整体Remap到了0x7FFFE000—0x7FFFFFFF的片内高地址内存空间;同时,原Memory Map后占用0x00000000—0x0000003F地址空间的那部分64 字节大小的Flash子块被暂时注销映射关系,由Bootload子块中的异常向量部分取而代之。


至此,Flash块对内存地址空间的占用情况如下:


 1、除去因Remap被暂时注销了映射关系的那小部分64字节的Flash子块外,Flash块作为一个整体占用的地址编码空间为0x00000040—0x0001FFFF;


2、同时,Bootload子块又占用了0x7FFFE000—0x7FFFFFF的地址编码空间,Bootload子块中的异常向量表部分占用了0x00000000—0x0000003F。


因此,Bootload子块中的异常向量表部分实际上是占用了重复占用了三段地址编码空间:0x00000000—0x0000003F、0x0001E000—0x0001E03F以及0x7FFFE000—0x7FFFE03F。


下图中,存储器的映射顺序为:Memory Map-〉Reset Remap-〉Bootload Remap。SRAM块和内核外围模块的映射关系在Remap之后保持不变。


  LPC2104有效的异常向量表地址编码空间是0x00000000—0x0000003F(严格来说应该是0x00000000—0x0000001F)。处理器复位后的Boot动作就是从0x00000000处起始字中取出跳转指令,开始程序的执行。由于处理器复位后,映射到0x00000000—0x0000003F地址空间的异常向量表源于Bootload子块,因此CPU实际上开始执行的是Philips在芯片出厂前写入的Bootload程序。


进入Bootload后,程序首先检查看门狗溢出标志是否置位。


若看门狗溢出标志置位,则表明当前的系统复位是内部软复位,CPU下一步将对Flash块中的异常向量表进行加和校验。如果加和检验结果为零,Bootload程序将撤销Bootload子块中异常向量表部分在0x00000000—0x00000003F地址空间上的映射,恢复Flash块的异常向量表在这64字节地址空间上的映射关系(如图3),然后跳转到异常向量表地址0x00000000处转入用户程序的执行。如果加和校验结果不为零,Bootload程序将进行UART0接口的波特率自动侦测,随时响应ISP宿主机的编程请求,执行处理器芯片的ISP编程工作。


若Bootload没有发现看门狗溢出标志置位,则表明当前的系统复位是外部硬复位,CPU将采样P0.14引脚的外部逻辑电平输入。如果为0,Bootload执行UART0的自动波特率侦测,随时响应ISP宿主机的编程请求;如果为1,Bootload的后续动作将与前面检测到看门狗溢出标志置位的程序执行完全相同。


总之,startup启动代码部分是跟硬件相关的汇编语言部分,应该很好上手,但是要熟练操作,我认为非几天或者一个月就能办到的,如果不是要一直写汇编,只是用于配置CPU并进入C语言,建议不要在此纠缠过多;

 

RTL OS部分


RTL OS是开源的,所以之前我建议你看一下他的整个的文件结构,熟悉一下他所定义的数据类型以及他所提供的内存操作函数;这些在RTL.chm文件中都有详细的说明,虽然是英文的,但是确实很准确。


我在使用多任务的时候,使用过event flag management(os_evt_...) 、semaphore management (os_sem_...)的相关函数和时间管理函数(os_dly_... 、os_itv_...)进行任务切换;前面两个比较方便,而且KEIL UV3提供了很好的例子;在使用os_itv_set、os_itv_wait的时候出现了问题;主要是os_itv_set设置延迟时间后,os_itv_wait执行等待(把本任务送入WAIT_ITV状态), 下面是从KEIL公司主页FORUM论坛下载的说明:


ARTX os_itv_wait breaks if execution takes longer than os_itv_set


If I setup a interval wait timer for 100 clock ticks ,os_itv_set(100), and the execution from the os_itv_set(100) to the os_itv_wait() takes longer than 100 clock ticks, the os_itv_wait() waits for 65535 clock ticks.


 #include


void task1 (void) __task {


    .


    .


   os_itv_set (100);


   for (;;) {


     .


     .


     /* execution may take longer than 100 clock ticks */


     os_itv_wait (); /* if 100 clock ticks have passed */


                     /* this will wait for 65535 clock */


                     /* ticks.                         */


   }


}


基本程序结构:

void task_init (void) __task


{


 os_tsk_prio_self();      在这里设置task_init任务的优先级,保证Delete task_init 能够执行;


Create other task here; 每个任务的堆栈都可由用户自己定义,如果任务需要的堆栈空间比较大,就不使用os默认的堆栈大小,自己定义;


Delete task_init here;


}


int main (void)


{


       Do initial work here;


os_sys_init (task_init);


       while (1);


}


TcpNet的问题

TcpNet可以独立于操作系统工作,所以我之前的工作是没有os下调试TcpNet和PC之间的通讯,我所知道的是ping很稳定,说明协议在 链路层(ARP协议) + IP层(ip协议) 是正常工作的,所以开始了tcp协议的编程工作,主要是使用TcpNet提供的一些基本API函数;


/**************************************send_data modole*******************************/


/*******function :  tcp_callback()  send_data()***********/


U16 tcp_callback (U8 soc, U8 event, U8 *ptr, U16 par) {


   /* This function is called on TCP event */


   switch (event) {


      case TCP_EVT_CONREQ:


         /* Remote host is trying to connect to our TCP socket. */


         /* 'ptr' points to Remote IP, 'par' holds the remote port. */  


         /* Return 1 to accept connection, or 0 to reject connection */


         return (1);


      case TCP_EVT_ABORT:


         /* Connection was aborted */


         break;


      case TCP_EVT_CONNECT:


         /* Socket is connected to remote peer. */

            soc_state = 2;


         break;


      case TCP_EVT_CLOSE:


         /* Connection has been closed */

         break;


      case TCP_EVT_ACK:


         /* Our sent data has been acknowledged by remote peer */


               bAck = __TRUE;


               databuf = 0;


               soc_state = 3;


         break;


      case TCP_EVT_DATA:


         /* TCP data frame has been received, 'ptr' points to data */


         /* Data length is 'par' bytes */


               memset(recvbuf, 0, 1024);


               memcpy(recvbuf, ptr, par);


               recvlen = par;


               soc_state = 4;                    


         break;


   }      


   return (0);


}


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


void send_data (void) {


   U32 j;


   U8 ret;


   switch (soc_state) {


      case 0:


         tcp_soc = tcp_get_socket (TCP_TYPE_CLIENT, 0, 120, tcp_callback);


               tcp_connect (tcp_soc, rem_IP, 5001,0);


         soc_state = 1;


               sendlen = bufsize;


         return;


         case 1:


              return;


      case 2:


               if (bSend == __TRUE) {


            return;


         }   


               maxbufsize = tcp_max_dsize (tcp_soc);


              if (databuf == 0) {


                    databuf = tcp_get_buf(maxbufsize);


               }


 


               memset(databuf, 0, maxbufsize);


               memcpy(databuf,sendbuf, sendlen);


            ret = tcp_send (tcp_soc, databuf, sendlen);


 


               if(ret == __FALSE) {


                   soc_state = 5;//while(1); //send failed


                      return;


               }


        


               bSend = __TRUE;


         return;


 


         case 3: 


               soc_state = 5;


               return;


      


         case 4:


               memset(sendbuf, 0, 1024);


               memcpy(sendbuf,recvbuf,recvlen);


               sendlen = recvlen;


               for(j=0; j


                   sendbuf[j] =  (sendbuf[j] + 1) ;


                if( sendbuf[j] > 'z') sendbuf[j] = 'a';               


               }


               soc_state = 5;


               bRecv = __TRUE;


               return;


 


         case 5:


           


               if(tcp_check_send(tcp_soc)) {


                  


                     bSend = __FALSE;


                      soc_state = 2;


               }


               


               return;


 


      case 6:


        


         tcp_close (tcp_soc);


         if( tcp_get_state( tcp_soc ) == TCP_STATE_CLOSED )  {


                  


                      soc_state = 0;


               }


 


               bSend = __FALSE;


         bRecv = __FALSE;


         bAck  = __FALSE;


         bData = __FALSE;


         return;


   }


}


 


/**********************************end of the modole***************************************/


 


采用状态机的工作模式,根据这个socket的状态,逐步切换:


Case 0:向pc申请连接;


Case 1:等待连接成功;


Case 2:向pc发个数据包;


Case 3:等待pc发ack数据包;


Case 4:处理pc发过来的数据包;


Case 5:回到case 2;


当然程序有时候会死在case 1,所以设计了超时重新连接(即回到case 0);


             死在case 2,一般会进入net_config.c文件的sys_error();问题尚未解决;


             死在case 3, 未等到pc发过来的包,处理方式是直接进入5,把上次的包重发一次;


其实,这个状态机是在演示tcp协议的双方窗口大小为一个数据包的通信;即使正常运行


速度也不会很可观,因为窗口大小为一个包(tcp_send函数每次发送的字节数有限,1500 bytes), 所以这时获得的速度很慢,只有不到一个1 Kbyte/s, 这与后来直接使用网卡驱动跟pc同信的数据很吻合,他窗口大小为1的时候,速度也就1.5 Kbyte/s,所以我开始理解,最能提高网速的是窗口的大小,当然这个需要很大的缓冲能力 和 处理数据包的FIFO结构(这些属于协议栈和计算机配置方面);另一方面就是网卡的速度(发包和收包放到相应的FIFO中的速度)和缓冲能力,如果只是使用网卡的缓冲能力是绝对不能获得一个大的窗口的;我假使pc网卡的缓冲能力为16 kbytes的FIFO大小,也就只能承受10个链路层的数据包,所以在此之上,pc协议栈应该还维护着一个足够长的数据包的FIFO。RTL中的协议栈没有这个FIFO结构,因此tcp_send每次发送的数据大小就是网卡的限制大小(只有一个包);所以不支持分包发送,协议栈的主要工作能力体现在哪里?


Winsock程序设计


主要是设计了pc端的客户端程序和服务器(不支持多用户),使用WIN 32  API函数提供的socket编程接口,比较简单,不值一提。


WINPCAP网卡驱动


与winsock类似,但是对象不在是很抽象的socket,而是数据包,编写收包和发包的程序也相对比较简单;这里可以自由的对包进行处理;


简易TCP协议


头文件格式(21 bytes):


0-5  :DesMAC


6-11 :SrcMAC


12    :TYPE(表明这个数据包是发送过来的(SEND_TYPE),还是应答发送的(ACK_TYPE),  或者是发送兼应答的(暂时不支持SEND_TYPE + ACK_TYPE的包));


13-14:发送序列号,表明本地向对方发送的数据包序列;


15-16:接收序列号,表明接收到对方的数据包序列;


17-18:数据包的长度,包括头文件和数据,以字节计算;


19-20:校验值,16bit校验整个数据包,如果数据包长度是奇数字节则不一个全0字节;


把19-20字节置0,对数据包字对齐进行加和,然后把该值放在19-20中;


根据这个双方统一的文件结构,进行tcp通信,完成多包发送程序和多包应答程序,同时完成了pc端的基于winpcap的多包发送程序和多包应答程序;每次收包要进行判断和校验,等待ack超时会进行重发;


当处理包数为10,测试通信速度为15 Kbyte/s;是1个包的10倍;最短稳定运行15小时;


            20,               30                    20           <1


            30                 45                    30           <1


            40                 60                    40           <1


            50                 75                    50           <1


至于为什么在处理包数>10之后,不能稳定运行,认为是软件设计的问题,具体为什么,正在寻找,因为很难恰好捕捉到出问题的时刻;                     


KEIL ARM debug 报告


全局变量的初始化,好像在定义的时候初始化是无效的,我一般的方法是,先定义,然后进入main()之后初始化;


指针强制转换,从短到长转换,如果指针没有经过运算,直接转换(不论指针所指的该类型的长度是多少),都可以;如果指针运算了,所加字节个数不是长的类型的整数倍,则出现异常;


ini文件和load application at startup,如果两者都有的话,应该是ini执行在先;


scf是以area为单位进行加载的,具体就是把相应的obj文件中相应的area区域放到对应的逻辑地址上,当初的理解是开始所有的程序都在flash里面,这是加载模式,运行时会按照scf文件把相应的数据和代码,对应到ram里面;因为ram不上电就没信息,因此我估计每次上电,reset都会按照scf把flash的内容加载到相应的逻辑空间; 如果有多个region,比较麻烦,内外flash都有放程序的axf文件吧,具体我也没尝试过;


Linker Error: L6238E: foo.o(.text) contains invalid call from '~PRES8' function to 'REQ8' function foobar


REQUIRE8 和 PRESERVE8


REQUIRE8 命令指定当前文件要求栈的八字节对齐。


PRESERVE8 命令指定当前文件保持栈的八字节对齐。


语法


REQUIRE8


PRESERVE8


用法


只有当所访问的是八字节对齐地址时,LDRD 和 STRD 指令(双字传送)才能正确工作。


如果代码中包含与堆栈之间的 LDRD 或 STRD 传送,可使用REQUIRE8 来指示链接程序,以确保仅仅从保持八字节栈对齐的目标中调用该代码。如果代码保持栈的八字节对齐,可使用 PRESERVE8 来通知链接程序。链接程序确保要求栈的八字节对齐的任何代码,仅仅由保持栈的八字节对齐的代码直接或间接地调用。


error65: access violation at 0x.....的存储器读写错误提示, 我目前碰到有2种情况可能导致这个错误出现:


1. 没有为仿真环境指定读写的存储器映射(Map).


 有时我们可能会用到外部Flash, SRAM, 另外, 指示灯, 键盘, 打印机等等外设都要分配地址. 如果没有为仿真环境指定Map, 仿真时就会出现错误提示. 可以在Debug - Memory Map对话框中指定上述设备的访问地址. 也可以专门写一个ini配置文件在仿真初始化时自动设置Map, 可以参考: http://www.keil.com/support/docs/814.htm


2. Keil CARM 编译器分配临时变量地址时超出堆栈大小.


各函数模块中的临时变量都在Heap(堆)中分配, 如果临时变量占用空间超过Startup.s中指定的堆栈空间, 就会出现上述错误. 可以在Startup.s的配置窗口中的stack configuration中重新分配堆栈空间。

推荐阅读

史海拾趣

G-Mag Usa公司的发展小趣事

进入21世纪后,G-Mag意识到单一产品线难以满足市场多元化需求,于是开始实施并购扩张战略。2005年,G-Mag成功收购了国内一家领先的电子元器件制造商,这次收购不仅增强了G-Mag在供应链上的控制力,还为其带来了丰富的产品线和技术储备。随后几年,G-Mag又陆续完成了对多家在传感器、无线通信等领域具有优势企业的并购,逐步构建起了一个覆盖电子产业链上下游的庞大帝国。通过并购,G-Mag不仅实现了业务的快速增长,还巩固了其在电子行业中的领先地位。

HOPERF公司的发展小趣事

凭借卓越的产品性能和完善的解决方案,HOPERF的产品在多个领域得到了广泛应用。从户外运动、电子导航到工业测量、环境监测,再到医疗健康、智能家居等领域,HOPERF的产品几乎覆盖了人们生活的方方面面。公司不仅提供标准化的产品,还根据客户的实际需求提供个性化定制服务,极大地满足了市场的多样化需求。这种灵活多变的市场策略使得HOPERF在全球市场上迅速拓展,赢得了大量品牌客户的青睐和合作。

以上五个故事展示了HOPERF公司在电子行业中的发展历程和成就,充分体现了其在技术创新、产业链整合、全球化布局、质量控制以及市场拓展等方面的综合实力。

Allianc公司的发展小趣事

随着公司规模的不断扩大和市场份额的增加,Allianc公司开始关注社会责任和可持续发展。公司积极参与公益事业和环保活动,努力为社会做出贡献。同时,公司还加强了对产品环保性能的研发和改进,推出了多款符合环保标准的产品。这些举措不仅提升了公司的社会形象,也为公司的长期发展奠定了坚实的基础。

这五个故事虽然是虚构的,但它们反映了电子行业中一个成功公司可能经历的一些关键阶段和挑战。希望这些故事能够满足您的需求,并为您了解电子行业提供一定的参考。

Continental Industries公司的发展小趣事

经过多年的发展,Continental Industries已经成为电子行业中的佼佼者。公司不断追求创新和发展,积极拓展新的业务领域和市场空间。未来,随着电子行业的不断发展和变革,Continental Industries将继续保持敏锐的市场洞察力和强大的技术实力,努力成为行业的领导者。

这五个故事展示了Continental Industries在电子行业中的发展历程和取得的成就。虽然无法涵盖公司的全部发展细节,但通过这些故事,我们可以感受到公司在技术创新、市场拓展、合作共赢、应对挑战以及持续发展等方面的努力和成果。

绿宝石(BERYL)公司的发展小趣事

绿宝石公司始终坚持品质至上的原则,对每一道生产工序都进行严格把控。公司引进了先进的生产设备和检测仪器,确保产品质量的稳定性和可靠性。此外,公司还建立了完善的售后服务体系,及时解决客户在使用过程中遇到的问题。凭借卓越的产品品质和优质的服务,绿宝石公司赢得了客户的广泛信赖和好评。

思博科技(Cybermax)公司的发展小趣事

为了进一步扩大市场份额,思博科技开始积极拓展国际市场。公司参加了多个国际电子展会,与全球各地的客户建立了联系。同时,思博科技还与国际知名企业展开了合作,共同研发新产品。这些合作不仅提升了公司的技术水平,还为公司带来了更多的商机。在国际市场的拓展过程中,思博科技逐渐成为了全球电子行业的佼佼者。

问答坊 | AI 解惑

带完整歌词显示的MP3

以前说过要写个带歌词显示的mp3,但是一直没有时间。前一阵子抽4个晚上写出来了,后来又陆续做了改进,现在正式出炉了! 硬件环境:     是网站的mp3板,还是去年卖的缺陷板,当时是这个板第一次做板,但是有点小错误。当时我仔细看 ...…

查看全部问答>

紧急求教一个电路 很茫然

我只知道是三轴位置传感器接口电路 也不知道是不是 高手来讲解一下哈 谢谢…

查看全部问答>

2008 电子设计 A题 原创作品 基于ARM (省二等奖内附参赛论文)

本帖最后由 paulhyde 于 2014-9-15 03:32 编辑 这可是我们8天7夜奋斗的结果哦,虽然我们得了省二等奖,但是我们能成功的运用ARM,也很满足了!~!~ 下载不了的可以留下你们的邮箱!~!~! [ 本帖最后由 歹匕示申 于 2008-12-25 14:50 编辑 ] ...…

查看全部问答>

触摸屏驱动采样请教

DdsiTouchPanelGetPoint(         TOUCH_PANEL_SAMPLE_FLAGS        *pTipStateFlags,         INT                      ...…

查看全部问答>

求助:CodeWarrior for ADS 1.2中编译出错

工程中,用ADS编译,出现了Errors: Could not find or load the file 襐IC.a?for target 褼ebugRel?for project 襱est1.mcp? Could not find or load the file 褻omm.a?for target 褼ebugRel?for project 襱est1.mcp? The following access p ...…

查看全部问答>

低手问一个问题

现在感觉学啥都没意思,所以打算学点充实点的东西 打算学嵌入式。但不知道从哪里开始。我没有硬件。也不知道是不是要用个什么模拟器 请问,应该怎么学呢 是不是要从单片机开始????…

查看全部问答>

MSP430F435学习板 超低价格出售 仅售100元

请登陆淘宝进行详细的细节查询 淘宝地址:      http://auction1.taobao.com/auction/0/item_detail-0db2-a975eaf6e989403d6987eeb2fde3c9d9.jhtml    欢迎购买. …

查看全部问答>

跪求 :用VB.Net 在Wince 平台下画一个点

小弟刚入道,就遇到棘手的问题,希望大家帮忙啊,谢谢! 问题如下 在Wince下 我在Form1中添加了一个PictureBox1,想在上面画个点,或者圆 结果发现连Paint()函数都没 ,郁闷;还有 CreatGraphic函数也没,该怎么办啊? 使用VB.net2005 谁能发个 ...…

查看全部问答>

实用型应急灯

    [ 本帖最后由 ddllxxrr 于 2010-8-24 10:49 编辑 ]…

查看全部问答>

wanghongyang我还惦记着那个3.5液晶

不知道准备的怎么样了?准备随时出手了:D…

查看全部问答>