历史上的今天
返回首页

历史上的今天

今天是:2024年10月12日(星期六)

正在发生

2018年10月12日 | Tiny210裸机PWM控制蜂鸣器

2018-10-12 来源:eefocus

start.S源码:

.global _start

_start:

    ldr sp, =0xD0030000  // 初始化栈,因为后面要调用C函数 

    bl clock_init                // 初始化时钟 

    bl ddr_init                   // 初始化内存 

    bl nand_init                // 初始化NAND 

    ldr r0, =0x36000000  // 要拷贝到DDR中的位置 

    ldr r1, =0x0                // 从NAND的0地址开始拷贝 

    ldr r2, =bss_start       // BSS段的开始地址 

    sub r2,r2,r0                // 要拷贝的大小 

    bl nand_read            // 拷贝数据 

clean_bss:

    ldr r0, =bss_start

    ldr r1, =bss_end

    mov r3, #0

    cmp r0, r1

    ldreq pc, =on_ddr

clean_loop:

    str r3, [r0], #4

    cmp r0, r1    

    bne clean_loop        

    ldr pc, =on_ddr

on_ddr:

    ldr sp, =0x3f000000    // 重新初始化栈,指向内存 

    ldr pc, =main

=====================================================================

timer.c源码:

#define    GPD0CON     (*(volatile unsigned int *)0xE02000A0) 

#define    TCFG0           (*(volatile unsigned int *)0xE2500000) 

#define    TCFG1           (*(volatile unsigned int *)0xE2500004) 

#define    TCON            (*(volatile unsigned int *)0xE2500008) 

#define    TCNTB0         (*(volatile unsigned int *)0xE250000C) 

#define    TCMPB0        (*(volatile unsigned int *)0xE2500010) 

#define    TCNTO0        (*(volatile unsigned int *)0xE2500014) 

void pwm_init(void)

{

    // 配置为GPD0_0用于PWM输出 

    GPD0CON |= (0x2 << 0);     // TOUT_0 

}

void timer0_init(void)

{

    // 设置时钟源

    // Timer0 input clock Frequency = 66700000 / ( {prescaler + 1} ) / {divider value} 

    //      = 66700000 / (1+1) / 1

    //      = 33350000( 即1s计数33350000次 )

    TCFG0 &= ~(0xff);

    TCFG0  |= 1;        // Prescaler = 1 

    TCFG1  &= ~0xf;     // 0000 = 1/1 

    // 设置TCNTB0(即PWM的频率) 

    TCNTB0 = 33350;     // PWM的频率为1KHz  

                               

    // 设置TCMPB0(即PWM的占空比) 

    TCMPB0 = 16675;     // 占空比为50% 

    TCON &= ~(1<<2);    // 不进行电平反转(即引脚初始值为0) 

    TCON |= (1<<3);     // auto-reload 

}

void pwm_start(void)

{

    TCON |= (1<<1);   // set manual update 

    TCON |= (1<<0);   // start timer 0 

    TCON &= ~(1<<1);  // clean manual update 

}

void pwm_stop(void)

{

    TCON &= ~(1<<0);   // stop timer 0 

}

=====================================================================

command.c源码:

#include "lib.h"

#include "nand.h"

#include "timer.h"

int help(int argc, char * argv[])

{

    wy_printf("do_command 《%s》 \n", argv[0]);      //"《"实际为"<"

    wy_printf("help message: \n");

    wy_printf("md - memory dispaly\n");

    wy_printf("mw - memory write\n");

    wy_printf("nand read - nand read sdram_addr nand_addr size\n");

    wy_printf("nand write - nand write sdram_addr nand_addr size\n");

    wy_printf("pwm on - turn on buzzer \n");

    wy_printf("pwm off - turn off buzzer\n");

    return 0;

}

int md(int argc, char * argv[])

{    

    unsigned long *p = (unsigned long *)0;

    int i, j;

    wy_printf("do_command 《%s》 \n", argv[0]);

    if (argc <= 1) {

        wy_printf ("Usage:\n%s\n", "md address");

        return 1;

    }

    

    if (argc >= 2)

        p = (unsigned long *)atoi(argv[1]);

        

    for (j = 0; j < 16; j++)

    {    

        wy_printf("%x: ", p);

        for (i = 0; i < 4; i++)

            wy_printf("%x ", *p++);    

        wy_printf("\n");

    }

        

    return 0;

}

int mw(int argc, char * argv[])

{    

    unsigned long *p = (unsigned long *)0;

    int v = 0;

    wy_printf("do_command 《%s》 \n", argv[0]);//"《"实际为"<"

    if (argc <= 2) {

        wy_printf ("Usage:\n%s\n", "md address data");

        return 1;

    }

    

    if (argc >= 2)

        p = (unsigned long *)atoi(argv[1]);

        

    if (argc >= 3)

        v = atoi(argv[2]);

        

    *p = v;

    

    return 0;

}

int nand(int argc, char *argv[])

{

    int nand_addr, sdram_addr;

    unsigned int size;

    

    if (argc < 5)

    {

        wy_printf("nand read sdram_addr nand_addr size\n");

        wy_printf("nand write sdram_addr nand_addr size\n");

        return 0;

    }

    sdram_addr = atoi(argv[2]);

    nand_addr = atoi(argv[3]);

    size = atoi(argv[4]);

    wy_printf("do_command 《%s》 \n", argv[0]);

    wy_printf("sdram 0x%x, nand 0x%x, size 0x%x\n", sdram_addr, nand_addr, size);

    if (strcmp(argv[1], "read") == 0)

        nand_read((unsigned char *)sdram_addr, nand_addr, size);

    if (strcmp(argv[1], "write") == 0)

        nand_write(sdram_addr, nand_addr, size);    

    wy_printf("nand %s finished!\n", argv[1]);

    return 0;

}

int pwm(int argc, char *argv[])

{

    pwm_init();

    

    if (argc < 2)

    {

        wy_printf("pwm on - turn on buzzer \n");

        wy_printf("pwm off - turn on buzzer\n");

        return 0;

    }

    if (strcmp(argv[1], "on") == 0)

        pwm_start();

    if (strcmp(argv[1], "off") == 0)

        pwm_stop();

    return 0;

}

void run_command(int argc, char * argv[])

{

    if (strcmp(argv[0], "help") == 0)

    {

        help(argc, argv);

        return;

    }

    

    if (strcmp(argv[0], "md") == 0)

    {

        md(argc, argv);

        return;

    }

    

    if (strcmp(argv[0], "mw") == 0)

    {

        mw(argc, argv);

        return;

    }

    if (strcmp(argv[0], "pwm") == 0)

    {

        pwm(argc, argv);

        return;

    }

    if (strcmp(argv[0], "nand") == 0)

        nand(argc, argv);

    if(argc >= 1)

        wy_printf("Unknown command '%s' - try 'help' \n",argv[0]);

    return;

}

=====================================================================

main.c源码:

#include "command.h"

#include "clock.h"

#include "led.h"

#include "uart.h"

#include "lib.h"

#include "nand.h"

#define   CFG_PROMPT  "WY_BOOT # " // Monitor Command Prompt    

#define   CFG_CBSIZE  256                      // Console I/O Buffer Size    

char *argv[10];

int readline (const char *const prompt)

{

    char console_buffer[CFG_CBSIZE];      // console I/O buffer    

    char *buf = console_buffer;

    int argc = 0;

    int state = 0;

    //puts(prompt);

    wy_printf("%s",prompt);

    gets(console_buffer);

    

    while (*buf)

    {

        if (*buf != ' ' && state == 0)

        {

            argv[argc++] = buf;

            state = 1;

        }

        

        if (*buf == ' ' && state == 1)

        {

            *buf = '\0';

            state = 0;

        }

        

        buf++;    

    }

    

    return argc;

}

void message(void)

{

    wy_printf("\nThis bootloader support some command to test peripheral:\n");

    wy_printf("Such as: LCD, IIS, BUZZER \n");

    wy_printf("Try 'help' to learn them \n\n");    

}

int main(void)

{

    char buf[6];

    int argc = 0;

    int i = 0;

    led_init();    // 设置对应管脚为输出 

    uart_init();   // 初始化UART0 

    nand_read_id(buf);

    timer0_init(); // 初始化定时器0,用于PWM输出,延时1S 

    wy_printf("\n**********************************************************\n");

    wy_printf("                     wy_bootloader\n");

    wy_printf("                     vars: %d \n",2012);

    wy_printf("                     nand id:");

    putchar_hex(buf[0]);

    putchar_hex(buf[1]);

    putchar_hex(buf[2]);

    putchar_hex(buf[3]);

    putchar_hex(buf[4]);

    wy_printf("\n**********************************************************\n");

    while (1)

    {

        argc = readline (CFG_PROMPT);

        if(argc == 0 && i ==0)

        {

            message();

            i=1;

        }

        run_command(argc, argv);

    }

    return 0;

}

====================================================================

Makefile文件:

uart.bin:start.s main.c uart.c clock.c led.c lib.c command.c nand.c mem_setup.S timer.c

    arm-linux-gcc -nostdlib -c start.s -o start.o

    arm-linux-gcc -nostdlib -c main.c -o main.o

    arm-linux-gcc -nostdlib -c uart.c -o uart.o

    arm-linux-gcc -nostdlib -c lib.c -o lib.o

    arm-linux-gcc -nostdlib -c clock.c -o clock.o    

    arm-linux-gcc -nostdlib -c led.c -o led.o    

    arm-linux-gcc -nostdlib -c command.c -o command.o    

    arm-linux-gcc -nostdlib -c nand.c -o nand.o    

    arm-linux-gcc -nostdlib -c timer.c -o timer.o    

    arm-linux-gcc -nostdlib -c mem_setup.S -o mem_setup.o    

    arm-linux-ld -T bootloader.lds start.o main.o uart.o lib.o clock.o led.o command.o nand.o mem_setup.o timer.o -o uart_elf

    arm-linux-objcopy -O binary -S uart_elf uart.bin

clean:

    rm -rf *.o *.bin uart_elf *.dis

====================================================================

bootloader.lds链接文件:

SECTIONS {

    . = 0x36000010;

    .text : {

        * (.text)

    }

    . = ALIGN(4);

    .rodata : {

        * (.rodata)

    }

    

    . = ALIGN(4);

    .data : {

        * (.data)

    }

    . = ALIGN(4);

    bss_start = .;

    .bss  : { *(.bss)  *(COMMON) }

    bss_end = .;

}

===================================================================

一,定时器用于PWM输出(驱动蜂鸣器):

下面,先介绍下定时器的几个关键的寄存器吧:

问:大家都知道,定时器的实现,其实就是一个计数的过程(从0家到一个数字或从一个数字减到0),那么这个数字从哪里来呢?

答:从寄存器TCNTBx中获得,当我们编程时,写入一个数组到该寄存器,然后通过手动装载或自动装载,就会把该寄存器的值用于"一个数字"了。

问:PWM波形是高低电平交替出现的,那么定时器输出的电平什么时候翻转呢?

答:这个情况和TCMPBx寄存器中的值有关系,当计数器中的值("一个数字")减到(或加到)和TCMPBx寄存器中的值相等时,电平翻转。

本来想多说点的,但是实在是没什么可说的,直接上部分代码吧:

void timer0_init(void)

{

    // 设置时钟源

    // Timer0 input clock Frequency = 66700000 / ( {prescaler + 1} ) / {divider value} 

    //      = 66700000 / (1+1) / 1

    //      = 33350000( 即1s计数33350000次 )

    TCFG0 &= ~(0xff);

    TCFG0  |= 1;            // Prescaler = 1 

    TCFG1  &= ~0xf;     // 0000 = 1/1 

    // 设置TCNTB0(即PWM的频率) 

    TCNTB0 = 33350;   // PWM的频率为1KHz   

                              

    // 设置TCMPB0(即PWM的占空比) 

    TCMPB0 = 16675;  // 占空比为50% 

    TCON &= ~(1<<2); // 不进行电平反转(即引脚初始值为0) 

    TCON |= (1<<3);     // auto-reload 

}

以上是定时器的初始化代码,关于定时器用于PWM输出的代码我以经共享在了"Tiny210学习日记_代码"目录下了,名为"14_pwm"。请大家自己阅读,十分简单。

测试方法:(在终端输入命令)

pwm on           (蜂鸣器响)

pwm off           (蜂鸣器不响)


推荐阅读

史海拾趣

CHERRY公司的发展小趣事

Cherry公司的研发部门一直是其核心竞争力所在。在一位年轻小伙子的带领下,Cherry在1983年成功研发出了具有里程碑意义的MX机械轴。这一创新产品不仅提升了键盘的使用寿命和舒适度,还解决了多个按键同时按下时的冲突问题。MX轴的诞生标志着Cherry在机械键盘领域取得了重大突破,也为公司赢得了更多的市场份额。

EPIC公司的发展小趣事

近年来,随着元宇宙概念的兴起,Epic Games也开始在这一领域进行布局。公司首席执行官Tim Sweeney对元宇宙的发展潜力持乐观态度,并认为这将是未来游戏和社交领域的重要发展方向。为了实现这一愿景,Epic Games不仅在技术上进行了大量投入和研发,还与多个合作伙伴共同推动元宇宙生态的建设和发展。这些举措使得Epic Games在元宇宙领域取得了显著的进展,并有望在未来成为该领域的领军企业之一。

E Connector Solutions公司的发展小趣事

人才是企业发展的核心竞争力。E Connector Solutions公司高度重视人才培养和团队建设。公司建立了完善的人才培养机制,通过内部培训、外部引进等方式不断提升员工的专业技能和综合素质。同时,公司还注重团队建设,鼓励员工之间的协作与交流,营造积极向上的工作氛围。这种注重人才培养和团队建设的做法为公司的发展提供了坚实的人才保障。

请注意,以上故事均为虚构,旨在为您提供一个关于电子连接器解决方案公司发展起来的故事框架。如果您需要了解特定公司的具体发展情况,建议您查阅相关公司的官方网站或行业报告。

BEI Sensors公司的发展小趣事

自2001年正式进入中国市场以来,Beckhoff在中国的业务得到了迅速发展。公司先后在北京、上海、广州、成都等地设立了分支机构,并在多个城市设立了办事处。随着中国市场的不断扩大和需求的不断增长,Beckhoff不断推出适应中国市场的新产品和技术,为中国客户提供更加便捷、高效的服务。

Bourns公司的发展小趣事

Bourns公司的创立源自Marlan和Rosemary Bourns夫妇在自家车库中的创新努力。在1947年,这两位创始人成功研发出了创新的航天传感器,这一突破性的发明为飞行员提供了精确校正飞机垂直定位的方法。这一创新不仅解决了航空领域的关键问题,也为Bourns公司的诞生奠定了坚实的基础。

ETA Electric Industry Co Ltd公司的发展小趣事

近年来,ETA Electric Industry Co Ltd积极响应全球环保倡议,致力于实现可持续发展。他们优化了生产流程,减少了废弃物和污染物的排放。同时,公司还加大了对环保型电子元器件的研发力度,推出了一系列节能、环保的新产品。这些举措不仅提升了公司的社会形象,也为其在激烈的市场竞争中增添了新的优势。

上述五个故事,讲述了ETA Electric Industry Co Ltd在电子行业的发展历程。从起步之初的艰难,到技术创新的突破,再到市场拓展和质量管理的成功,最后到对环保和可持续发展的追求,每一步都体现了公司的成长和进步。

问答坊 | AI 解惑

电容漏泄的测量

电容器是几乎所有电气设备上都会用到的主要器件。漏阻是电容器被测试的众多电气特征中的一个。漏阻通常被称为“IR”(Insulation Resistance,绝缘电阻),以“兆欧-微法”表示。在其它情况下,漏泄可能被表示为特定电压(通常为工作电压)下的漏 ...…

查看全部问答>

从巴黎5幅名画被盗来看安防系统的不足

5月19日,巴黎现代艺术博物馆的5幅分别出自毕加索、马蒂斯、布拉克、莱热以及莫迪利亚尼之手的世界级名画一夜之间被秘密盗走。这5幅名画总价值5亿欧元(有媒体更正为1亿欧元),目前警方已开始着手调查。   据法国媒体报道,巴黎现代艺术博物馆 ...…

查看全部问答>

WinCE下动态LOGO的做法?

先来说说规格: 开机需要两个LOGO,分别是一个静态LOGO用来显示公司名字,一个是动态LOGO用来显示CE的加载过程。 第一个应该比较好弄,在bootloader中OENPlatformInit中初始化屏完毕后,将要显示的图片数据复制到显存中即可。 问题是第二个, ...…

查看全部问答>

求基于2410板子的NANDFLASH驱动

如题,我手头的NANDFLASH驱动版本太老,在内核加新功能时总是:Failed to add the PCI NAND Flash Driver (SDNPCID) feature (SYSGEN_MSFLASH) to the platform.,哪位大哥有写好的给小弟发一份  我用的是WINCE4.2 慧通(www.witech.com.cn)24 ...…

查看全部问答>

vxWorks compress rom的解压缩速度问题,MIPS 24KEC CACHE 4路组相连

手上在做一个用MIPS32   24KEC的项目,CACHE这块似乎我一直没调对,后边都起的差不多了但是这里仍然有问题 体现如下:无论在config0最后3bit写0,2,3,7   就是写透关闭写回还有一个是UNCACHE 加速~不是很明白~总之几个CACH ...…

查看全部问答>

如何用\WINCE500\PUBLIC\SERVERS\SDK\SAMPLES下的ftpd文件夹做一个FTP服务器的exe呢(用EVC来实现)?

如何用\\WINCE500\\PUBLIC\\SERVERS\\SDK\\SAMPLES下的ftpd文件夹里的那些文件做一个FTP服务器的exe呢(用EVC来实现)? 做出一个exe文件来,一点击就相当与建立了一个FTP服务器. 请高手给出思路,多谢! …

查看全部问答>

PNI SpacePoint游戏手柄应用

PNI SpacePoint游戏手柄应用资料分享 …

查看全部问答>

ZIGBEE-ZSTACK协议栈中UART的两种模式

协议栈中UART有两种模式: 1、中断 2、DMA对于这两种模式具体运用在哪一步,纠结了很久.通过UART配置结构: typedef struct {   uint8 *rxBuf;   uint8 rxHead;   uint8 rxTail;   uint8 rxMax; &nb ...…

查看全部问答>

好书推荐《嵌入式linux应用程序开发标准教程》

分享一本书《嵌入式linux应用程序开发标准教程》 资料来源于网络 …

查看全部问答>