day03 LED灯源程序编写与编译、UART原理

回顾:
面试题:谈谈对嵌入式的理解
1.明确:如何向下位机部署软件
  1.1.明确:嵌入式开发模式,画出简要的示意图
  1.2.看图明确接下来要完成的内容
      上位机搭建开发环境
          各种安装
      搞定下位机
              掌控硬件信息
                  粗看
                          三大件
                          外围
                  细看
                          原理图
                          手册
              部署uboot
                  TF卡
            掌握uboot常见的命令
                print
                    serverip
                    ipaddr
                setenv
                saveenv
                ping
                tftp
                update_mmc
                go  
                
2.面试题:谈谈对ARM处理器裸板编程的认识
  2.1.上来直接提出案例,阐述ARM裸板编程的流程。目前:先以LED开关灯为例,进行阐述解释说明 。
  2.2.明确相关概念
      计算机硬件层面包括:CPU和外设 。
      CPU一天到晚都是在跟外设进行数据通信。CPU访问外设都是以地址指针的形式访问
  2.3.紧接着分析用户需求。
      目前需求就是:开关灯
  2.4.掌控LED的硬件相关信息 。
      粗看:
          看位置
          硬件工程师
      细看:
          1.LED的原理图:
          通过原理图得到:

          1.1.务必画出一个简要的CPU访问操作LED的示意图。

                   

          1.2.看图阐述CPU核访问LED的流程
            CPU核以软件(地址指针)形式访问GPIO控制器内部的一大堆寄存器,本质就是给GPIO控制器发送控制操作命令 。
             
            GPIO控制器根据命令由硬件上自动操作对应的引脚(管脚)(无非就是高低电平)。
             
            引脚的状态(高/低电平)最终影响LED的状态(亮/灭)。
          1.3.结论:
                  接下来只要掌握GPIO控制器以及内部的一大堆寄存器的操作即可完成最终的LED的操作。
                  
          2.问:GPIO控制器以及内部一大堆的寄存器如何访问呢?
            答:由于GPIO控制器集成在S5P6818处理器的内部。要想知道GPIO控制器如何访问操作,只需看S5P6818处理器的芯片手册(说明书)。
        
        3.打开S5P6818处理器的芯片手册:
          resource/Datasheet/SEC_S5P6818X_Users_Manual_preliminary_Ver_0.00.pdf
          切记:尤其是处理器的芯片手册,只看跟目前研究的内容(GPIO控制器)相关的章节。

          结论:P739第16章讲解GPIO控制器


          3.1.看GPIO控制器相关的说明,罗列重要的跟将来软件操作相关的内容:
              1.S5P6818包含160个GPIO引脚
                分五组:A/B/C/D/E
                每一组:32个GPIO
                LED1对应的引脚为:GPIOC12(C组的第12个引脚)
              2.GPIO的输出操作,P742
                GPIO复用功能选择寄存器:指定GPIO引脚的复用功能 。
                GPIO输出使能寄存器:指定GPIO的输入或者输出功能 。
                GPIO输出寄存器:指定GPIO的输出值(0:低电平;1:高电平) 。
                结论:开关灯操作:
                1.首先配置GPIO复用功能选择寄存器,配置为GPIOC12这种功能 。
                2.然后配置GPIOC12为输出功能,配置GPIO输出使能寄存器 。
                3.最后:
                  开灯:配置GPIO输出寄存器为0
                  关灯:配置GPIO输出寄存器为1
                4.问:以上三个寄存器如何访问操作呢?
                  答:寄存器也是硬件,它同样是外设!
             3.相关寄存器的特性(P745):
               GPIOCOUT:输出寄存器
               基地址:0xC001C000
               BIT[12]=0:输出低电平,开灯
               *(volatile unsigned long *)0xC001C000 &= ~(1 << 12);                     
               美化:
               #define GPIOCOUT *(volatile unsigned long *)0xC001C000
               GPIOCOUT &= ~(1 << 12);
                
               BIT[12]=1:输出高电平,关灯
               GPIOCOUT |= (1 << 12);
                
               GPIOCOUTENB:输出使能寄存器
               基地址:0xC001C004
               BIT[12]=1:配置为输出功能
               #define GPIOCOUT (*(volatile unsigned long *)0xC001C004)
               GPIOCOUTENB |= (1 << 12);
                
               GPIOCALTFN0:复用功能选择寄存器0(P757)
               基地址:0xC001C020
               BIT[25:24]=01   //注意在P68  
               GPIOCALTFN0 &= ~(3 << 24);
               GPIOCALTFN0 |= (1 << 24);  
                
               至此:硬件信息的掌控完毕!
                
      2.5.一旦硬件信息掌控完毕,编写LED的操作软件
          1.明确:嵌入式软件开发分为两类
            裸板程序:
                    下位机不会运行操作系统(linux/windows/vxworks),运行的程序就一个,单任务运行 。
                    标准C的库函数一律不能使用,例如:printf。
                    
            基于操作系统程序:后续慢慢讲解
            结论:首先要明确LED的程序属于哪类。此时此刻,此LED程序为裸板程序。         
           
          2.明确:裸板程序的编程框架
            开发语言:一般C语言或者汇编 。
            “硬件初始化”:硬件外设正式工作之前,将其工作参数,工作状态配置完毕 。
            框架:
            //裸板程序的入口函数名随便定义,不一定非要是main
            void xxx(void) {
                    
                    //硬件初始化函数
                    xxx_init();
                    /*
                    led_init(); //初始化LED
                    uart_init(); //初始化串口
                    net_init(); //初始化网络
                    mmc_init(); //初始化EMMC
                    bt_init(); //初始化蓝牙
                    lcd_init(); //初始化LCD显示屏
                    ...
                    
                    */
                    
                    while(1) {
                         //做业务:根据用户需求,操作硬件外设
                         /*
                           led_on();
                           delay();
                           led_off();
                           delay();
                         */
                    }
            }        
               
          3.编写LED裸板程序,实现交替闪烁
            实施步骤:
            上位机执行:
            sudo chown tarena /opt -R
            sudo chgrp tarena /opt -R
            mkdir /opt/arm/day03/1.0 -p
            cd /opt/arm/day03/1.0
            vim led.h //声明
            vim led.c //定义
                   
                   注意:vim的使用
                   1.vim多屏显示(命令行模式下)
                 vs 文件名 //左右分屏
                 sp 文件名 //上下分屏
                 切换快捷键:ctrl + ww
          
                 复制粘贴:
                 shift+v:行选
                 ctrl+v:列选
          
                        
           
          4.问:如何编译LED的程序呢?
            答:明确:势必不能用gcc编译(针对于X86架构),所以:务必先在上位机部署添加交叉编译器。
                上位机添加ARM架构交叉编译器的流程:
                4.1.获取交叉编译器
                resource/编译器/arm-cortex_a9-eabi-4.7-eglibc-2.18.tar
                拷贝到linux和windows共享目录中
                cp arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz /opt/
                 
                4.2.上位机添加
                cd /opt/
                tar -xvf arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz
                得到新目录:arm-cortex_a9-eabi-4.7-eglibc-2.18
                mv arm-cortex_a9-eabi-4.7-eglibc-2.18 toolchains
                ls /opt/toolchains/bin/
                   arm-cortex_a9-linux-gnueabi-gcc //ARM架构的gcc编译器
                 
                sudo vim /etc/environment
                在PATH中添加/opt/toolchains/bin,例如:
                PATH=/opt/toolchains/bin:...
                保存退出
                 
                重启上位机linux系统
                 
                4.3.测试交叉编译器
                上位机执行:
                arm-cortex_a9-linux-gnueabi-gcc -v //查看交叉编译器的版本
                 
                4.4.交叉编译LED程序
                cd /opt/arm/day03/1.0
        arm-cortex_a9-linux-gnueabi-gcc -nostdlib -c -o led.o led.c
                说明:
                -nostdlib:告诉编译器,此程序不使用标准C库
                -c:只编译不链接

                

arm-cortex_a9-linux-gnueabi-ld -nostartfiles -nostdlib  -Ttext=0x48000000  -o  led.elf led.o

                说明:
                arm...ld:链接器
                -nostartfiles:告诉链接器,此代码无需启动文件
                -Ttext=0x48000000:告诉链接器,代码段的起始地址为0x48000000(下位机的内存地址)
                                -o led.elf:链接生成ELF格式的可执行文件
                                切记:此时此刻led.elf不能在没有操作系统的环境中运行
                                
                                arm-cortex_a9-linux-gnueabi-objcopy -O binary led.elf led.bin
                                说明:利用arm...objcopy工具将ELF格式的可执行文件
                                      再次获取到其中的真正的二进制文件信息
                                      led.elf:橘子(带皮)
                                      led.bin:果肉
                                      objcopy:去皮工具
                                       
                                cp led.bin /tftpboot //拷贝到下载目录
                                
                                绝招:反汇编
                     arm-cortex_a9-linux-gnueabi-objdump -D led.elf > led.dis  
                                led.dis:反汇编文件
                                vim led.dis //只需关注一个内容即可
                                <0x48000000>:led_test  
                        如果看到以上信息说明:led_test函数的地址为0x48000000。说明程序的编译是对的!
                                
                         5.下位机测试
                           重启下位机,进入uboot命令行模式,执行:
                           ping 192.168.1.8
                           tftp 48000000 led.bin
                           go 48000000
                        
                         6.验证入口地址特性
                           cd /opt/arm/day03/1.0
                           vim led.c //将delay函数的定义放在led_test函数定义的前面
                           保存退出
                           ①.arm-cortex_a9-linux-gnueabi-gcc -nostdlib -c -o led.o led.c
                           ②.arm-cortex_a9-linux-gnueabi-ld -nostartfiles -nostdlib  
                                       -Ttext=0x48000000 -o led.elf led.o
                           ③.arm-cortex_a9-linux-objcopy -O binary led.elf led.bin
                           ④.arm-cortex_a9-linux-objdump -D led.elf > led.dis
                           ⑤.vim led.dis  

                           查看0x48000000这个地址对应的函数是:led_test?delay?
                            
                           切记:编译器链接是从文件的头到尾进行链接(从上到下)
                            
                           作业:实现一个跑马灯
                           LED1亮->LED2亮->LED3亮->LED4亮->LED1灭->...
                            
                           作业:实现蜂鸣器的操作
************************************************
2.面试题:谈谈对UART的理解
  2.1.首先要交待计算机中常见的几种硬件通信方式
      硬件通信接口
      明确:计算中包括:CPU和外设。
            CPU一天到晚和外设进行数据交互通信
      问:CPU和外设数据通信的方式方法有哪些呢?
      答:计算机中CPU和外设进行硬件通信的方式
          通信接口有以下几种:
          1.GPIO通信方式,例如:LED灯,蜂鸣器等 。
          2.UART串口通信方式,例如:GPS,GPRS,BT等 。
          3.I2C总线通信方式,例如:重力传感器,三轴加速度传感器,触摸屏等 。
          4.SPI总线通信方式,例如:Norflash闪存,触摸屏等 。
          5.1-Wire(一线式)总线通信方式,例如:温度传感器,EEPROM存储器等 。
          所以:这里开始讲解UART,如果可以,也可以阐述一下I2C总线 。
    
   2.2.UART串口的定义
       定义就九个字:通用串行异步收发器 。
       进一步的对定义进行解释说明:
       “通用”:UART串口应用非常广泛
       ”串行“:CPU和外设进行数据通信时,只需一根信号线即可 。
              此信号线又称数据线,也就是说CPU和外设进行数据通信时,是一个bit位一个bit位的传输:
              切记:UART数据传输从低位开始!
              例如:CPU向BT发送一个0x95这个数据
              数据线的操作如下:
              高->低->高->低->高->低->低->高
              1   0   1   0   1   0    0  1

       顺便侃侃串行的死对头:并行

       “并行”:CPU和外设数据传输时,需要多根信号线(数据线),8/16/32根,那么也就是一次数据传输可以同时传输8bit/16bit/32bit

       顺便再看看并行和串行的对比:
       传输速度:一般来说并行快于串行 。
       传输距离:串行更适合远距离传输 。
       抗干扰性:串行抗干扰性更好。                                      
              
             “异步”:首先要明确:CPU的数据处理速度要远远快于外设。
                     所以CPU和外设进行数据传输时,务必要考虑数据同步。

                     “数据同步”:CPU向设备发送数据以后,要确保外设能够正常的将数据接收到,接收完整!

                     计算机中数据同步的方法有两种:异步和同步 。
                      
异步定义:双方在数据正式传输时,只要保证数据同步即可 。传输前和传输以后,无需考虑数据同步。异步具体如何实现数据同步关键在于协议中!这里待会儿讲讲UART的协议,即可了解何为异步!
                      
同步定义:CPU和外设进行数据传输时,如果采用同步方式保证数据同步,那么CPU和外设之间不仅仅有数据线,还需要一根时钟控制信号线,此信号线就是用来实现双方的数据同步,此时此刻,务必画图举例子说明即可!
                               参见:uart2.bmp
                               以CPU向外设LM77发送1和0为例:
                               CPU在时钟线为电平时,将数据1放到数据线上(拉高数据线)
                               设备就会在同周期的高电平从数据线上读取数据                                                    
                                         结论:低放高取
                                          
                收发器:接收和发送数据的硬件单元。        
                CPU给外设发送数据:
                        CPU就是发送器,外设就是接收器。
                外设给CPU发送数据:
                        外设是发送器,CPU是接收器 。
                        
 

你可能感兴趣的:(Tarena_ARM)