LED

一、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 Descr ip tion     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字节写入0x100
volatile 的作用,以及哪种场合需要使用该关键字?(课后查资料)
>>表示'一个变量也许会被后台程序意想不到的修改'。变量如果加了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 ~/.bashrc 5.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);
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值