LED

来源:互联网 发布:皮鞋设计软件 编辑:程序博客网 时间:2024/05/16 18:23
一、LED控制编程 1、电路原理图     【底板】env\DataSheet\x6818bv2.pdf       如果让LED1亮(D25),找到'对应标号'为GPIOC12为低电平       反之--------------------------------------高电平     【核心板】env\DataSheet\x4418cv3_release20150713.pdf       在核心板里面'搜索标号'GPIOC12       找到GPIOC12'导线接到对应CPU的管脚'W15上,或者说接到 CPU GPIOC12管脚上。 问题:     运行在ARM CORE (CPU)中的程序如何才能控制GPIOC12管教上电平的变化? 答案:     在CPU的说明书里面 DataSheet 文件夹中     :SEC_S5P6818X_Users_Manual_PReliminary_Ver_0.00.pdf <第16章> 2、CPU数据手册 --->P 56.   ' I/O Function Description     CPU上一共有 537 个管脚,<第16章>可用于通用GPIO的有 160 个管脚。 --->P 68.         W15 - Alternate Function1[功能1] - GPIOC12 - I/O >>硬件工程师使用CPU芯片时,关注CPU上的管脚 >>软件工程师使用CPU芯片时,关注'CPU内部的特殊功能寄存器'(register) >>每隔特殊功能寄存器都是32bit ' GPIO[X]00  ---> CPU手册GPIOx 00pin --->P 757. - 16.5.1.8 GPIOxALTFN0     GPIOCALTFN0 - bit[25:24] - 01=Function1 [01=功能1,即对应I/O功能]     Address: 0xc001c020 --->P 745. - 16.5.1.2 GPIOxOUTENB     GPIOCOUTENB - bit[12] - 1=Output Mode [0/1=输入/输出功能]     Address: 0xc001c004 --->P 745. - 16.5.1.1 GPIOxOUT     GPIOCOUT - bit[12] - 1=High Level [0/1=输出低/高电平]     Address: 0xc001c000 3、C语言回顾 - register     register 关键字     register int i;  // int i; 默认在内存数据段中,加register关键字就把变量i的这所占4个字节的存储空间放在CPU的寄存器中,可以加快变量i的访问速度 3.1 C语言指针
    int a = 100;    * (&a) = 100;    0xc001c000   // 常量    (int*)0xc001c000   // 地址    * ((int*)0xc001c000) = 0x100;   // 写入数据,按int-4字节写入0x100volatile 的作用,以及哪种场合需要使用该关键字?(课后查资料)>>表示'一个变量也许会被后台程序意想不到的修改'。变量如果加了volatile修饰,则会从内存重新装载内容,而不是直接从寄存器拷贝内容。volatile可以保证对特殊地址的稳定访问。>>寄存器地址要加volatile修饰,主要是因为寄存器里面的值是随时变化的。    我们读取数据的时候,CPU直接到内存里面取值,而不是到cache里面。    1) 并行设备的硬件寄存器;    2) 中断服务子程序中会访问到的非自动变量;    3) 多线程应用中被及格任务共享的变量;

例如:

    volatile int i = 10;    int a = i;    // 其他代码,并未告诉编译器,对i进行过操作    int b = i;"volatile 指出i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而不是重新从i里面读,这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说 volatile 可以保证特殊地质的稳定访问。"

    // 访问特殊功能寄存器的时候需要加 volatile 关键字,正确的写法:    a = * ((volatile unsigned int*)0xc001c000);    // 下面此条做法,不但将bit12清0,也导致其他的bit被清0了,错误!!    * ((volatile unsigned int*)0xc001c000) = 0x00;3.2 位运算    假设需要将 0xc001c020 寄存器的[25:24]bit位设置为 01 ,
    * ((volatile unsigned int*)0xc001c020) &= ~(0x03000000);  // 第一步    // 32bit :             xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx     // 0x03000000          0000 0011 0000 0000 0000 0000 0000 0000    // ~(0x03000000)       1111 1100 1111 1111 1111 1111 1111 1111    // &= ~(0x03000000)    xxxx xx00 xxxx xxxx xxxx xxxx xxxx xxxx    * ((volatile unsigned int*)0xc001c020) |= 0x01000000;  // 第二步    //  32bit : xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx     //                 01 ([25:24]bit)    //        0x0______01_0____0____0____0____0____0    "实际做法:"    * ((volatile unsigned int*)0xc001c020) &= ~(3<<24);  // 第一步    * ((volatile unsigned int*)0xc001c020) |= (1<<24);  // 第二步<tips>$:'file a.out// file 命令可以用来分析文件的一些属性。x86-64 是x86的64位平台运行。4. 编码    vi led.c
/** 代码演示 **/#define  GPIOC_OUT     *((volatile unsigned int*)0xc001c000)#define  GPIOC_OUTENB  *((volatile unsigned int*)0xc001c004)#define  GPIOC_ALTFN0  *((volatile unsigned int*)0xc001c020)void delay (unsigned int); void led_test (void) {    // 配置对应管脚为GPIO功能    GPIOC_ALTFN0 &= ~ (3 << 24); // clear bit 24,25    GPIOC_ALTFN0 |= (1 << 24); // set bit 24    // 选择为输出功能    GPIOC_OUTENB |= (1 << 12); // OUTPUT    while (1) {        // 亮 - 输出低电平        GPIOC_OUT &= ~ (1 << 12); // clear bit 12        delay (0x1000000);        // 灭 - 输出高电平        GPIOC_OUT |= (1 << 12); // set bit 12        delay (0x1000000);    }}// delay函数的实现不能放前面,只能先声明后实现void delay (unsigned int n) {    unsigned int i = 0;    for (i = n; i != 0; i--); // CPU执行空操作来耗时}

5. arm编译器

5.1 安装arm交叉编译器>>位置:/home/tarena/workdir/arm-linux-gcc/    'arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz    权限不够时解决方法:    1> $:' sudo ...    2> $:' sudo chmod +w /opt/ -R    3> $:' sudo chmod 777 /opt/ -R    // 将交叉编译器tar包文件拷贝到/opt/下,在此文件夹下解压缩    $:'cd ~/opt/    $:'sudo cp ~/workdir/arm..<table>/arm... .tar.gz .    $:'sudo tar xvf *.gz>>位置:/opt/arm-cortex_a9-eabi-4.7-eglibc-2.18/bin/    'arm-cortex_a9-linux-gnueabi-gcc    $:'vi ~/.bashrc>>添加:<shift + g> // 添加到文件尾    'PATH=$PATH:/opt/arm-cortex_a9-eabi-4.7-eglibc-2.18/bin    $:'source ~/.bashrc5.2 编译程序希望编译出来的程序不使用共享库 (因为是裸板)    1)编译    $:'arm-cortex_a9-linux-gnueabi-gcc -c -nostdlib led.c -o led.o    2)连接    $:'arm-cortex_a9-linux-gnueabi-ld -nostdlib -nostartfiles -Ttext=0x48000000 -eled_test led.o -o led        // -no stdlib 不连接标准库文件        // -no startfiles 不连接系统标准启动文件        // -Ttext 指定代码段的起始地址        // -e 指定入口点函数,默认找_start    3)去掉附加信息,生成二进制文件    $:'arm-cortex_a9-linux-gnueabi-objcopy -O binary led led.bin    $:' file led.bin<tips>$:'arm-cortex_a9-linux-gnueabi-readelf -d a.out// 显示可执行文件a.out文件中所需的共享库.so信息$:'arm-cortex_a9-linux-gnueabi-objdump -S led// 反汇编的命令,查看文件的具体的函数及信息6. 下载运行:  X6818# 命令行    $:' cp led.bin /tftpboot/    X6818#:'tftp 48000000 led.bin   // uboot下数字都识别为十六进制    X6818#:' go led.bin<tips>执行tftp 48000000 led.bin 时 Ubuntu-server报 T..T..T...时需重启服务器:$:'sudo /etc/init.d/tftpd-hpa restart补充:编程错误>>语法错误:    '只关注只解决第一个错误。逻辑错误:    ' printf / gdb    1. 是不是硬件问题?        env/led.bin放进去,灯亮硬件没问题(或者换到别人电脑上试一试)    2. 如果是软件问题,怎么查?        修改led.c的逻辑        让对应管脚一直输出高电平        拿万用表量一下对应的管脚上是否是高电平。env/BCompare-3.3.4.14431.zip   // 工具,对比文件夹和文件里面不同之处<tips>vi中的命令模式下:e ../xxx.c    // 在vi中直接打开别的文件练习:    1. LED1和LED2交替闪烁。(理清楚今天的整个流程,看手册,理流程)    2. beep蜂鸣器的控制管脚相关数据准备:'led1 - GPIOC12 - W15 - Function1    GPIOCALTFN0 - 0xc001c020 - bit[25:24] - 01=Function1 (I/O功能)    GPIOCOUTENB - 0xc001c004 - bit[12] - 1=Output Mode (输出功能)    GPIOCOUT - 0xc001c000 - bit[12] - 1=High Level (0/1 低高电平)'led2 - GPIOC7 - AE21 - Function1    GPIOCALTFN0 - 0xc001c020 - bit[15:14] - 01    GPIOCOUTENB - 0xc001c004 - bit[7] - 1    GPIOCOUT - 0xc001c000 - bit[7] - 1'led3 - GPIOC11 - W14 - Function1    GPIOCALTFN0 - 0xc001c020 - bit[23:22] - 01    GPIOCOUTENB - 0xc001c004 - bit[11] - 1    GPIOCOUT - 0xc001c000 - bit[11] - 1'led4 - GPIOB26 - MCU_SPI_WP AC25 - Function1 (暂略)
/** 代码演示 **/#define GPIOC_ALTFN0  *((volatile unsigned int*)0xc001c020)#define GPIOC_OUTENB  *((volatile unsigned int*)0xc001c004)#define GPIOC_OUT     *((volatile unsigned int*)0xc001c000)void delay (unsigned int);void led_run (void) {    // 配置GPIOC管脚    // led1 25:24    GPIOC_ALTFN0 &= ~ (3 << 24);    GPIOC_ALTFN0 |= (1 << 24);    // led2 15:14    GPIOC_ALTFN0 &= ~ (3 << 14);    GPIOC_ALTFN0 |= (1 << 14);    // led3 23:22    GPIOC_ALTFN0 &= ~ (3 << 22);    GPIOC_ALTFN0 |= (1 << 22);    // 设置输出功能    GPIOC_OUTENB |= (1 << 12);    GPIOC_OUTENB |= (1 << 11);    GPIOC_OUTENB |= (1 << 7);     for (;;) {        GPIOC_OUT &= ~ (1 << 12); // led1        delay (0x800000);        GPIOC_OUT &= ~ (1 << 11); // led2         delay (0x800000);        GPIOC_OUT &= ~ (1 << 7); // led3        delay (0x800000);        GPIOC_OUT |= (1 << 12);         delay (0x800000);        GPIOC_OUT |= (1 << 11);         delay (0x800000);        GPIOC_OUT |= (1 << 7);         delay (0x800000);    }   }void delay (unsigned int n) {    unsigned int i;    for (i = n; i; --i);}

    2. beep蜂鸣器的控制' beep蜂鸣器 - PWM2[GPIOC14] - AD12 - Function2    GPIOCALTFN0 - 0xc001c020 - bit[29:28] - 10=Function2 (I/O功能)    GPIOCOUTENB - 0xc001c004 - bit[14] - 1=Output Mode (输出功能)    GPIOCOUT - 0xc001c000 - bit[14] - 1=High Level (0/1 低高电平)

/** 代码演示 **/#define GPIOC_ALTFN0  *((volatile unsigned int*)0xc001c020)#define GPIOC_OUTENB  *((volatile unsigned int*)0xc001c004)#define GPIOC_OUT     *((volatile unsigned int*)0xc001c000)void delay (unsigned int);void beep_run (void) {    // 配置GPIO管脚    GPIOC_ALTFN0 &= ~(3 << 28);    GPIOC_ALTFN0 |= (2 << 28);    // 设置输出功能    GPIOC_OUTENB |= (1 << 14);    for (;;) {        GPIOC_OUT &= ~(1 << 14); // 低电平 - 鸣叫        delay (0x2000000);        GPIOC_OUT |= (1 << 14); // 高电平 - 不叫 (无延时和停止蜂鸣效果)        delay (0x2000000);    }   }void delay (unsigned int n) {    unsigned int i;    for (i = n; i; --i);}
 
原创粉丝点击