极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 25595|回复: 8

Arduino 代码机制

[复制链接]
发表于 2014-4-24 21:14:44 | 显示全部楼层 |阅读模式

        之前讲过了Arduino的各个配置文件,知道了各个板子是如何被Arduino识别到的。http://www.geek-workshop.com/forum.php?mod=viewthread&tid=9460&page=1#pid62525

       接下来就可以激动的开始写代码了,一定想测试测试自己的成果。可是打开Arduino就郁闷了,因为只看到了setup和loop函数,却没有基本的c函数。
void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:
}

       于是又开始好奇了,当然对于开源代码来说这个没有什么秘密。我们来问问代码就知道了。
       从上次配置文件的分析来看,核心代码肯定是在cores\arduino下边。进入代码目录可以看到这里各个文件都是按照功能来命名的,所以很好辨认。很容易就能找到main.cpp,我们打开来看看具体内容:
int main(void)
{
        init();

#if defined(USBCON)
        USBDevice.attach();
#endif
       
        setup();
   
        for (;;) {
                loop();
                if (serialEventRun) serialEventRun();
        }
        
        return 0;
}


       看到我们熟悉的main函数了吧,同时看到main函数里在初始化时调用了setup函数,在for循环里调用了loop函数,所以这下大家明白了为什么在arduino中写代码的时候只看到setup和loop函数了吧。

       接下来再打开一个最简单的例子Blink。
int led = 13;

// the setup routine runs once when you press reset:
void setup() {               
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

       这个代码原理很简单,把引脚13设置成输出,然后使用for循环,在13脚交替输出高低电平;这个逻辑很好理解。但是这其中又有疑问了;写过avr c代码的同学肯定都知道,一般对某个端口或者引脚操作都是使用DDRX,PORTX,PINX来操作的,为什么这里可以直接用数字来操作呢?
       接下来继续分析一下pinMode这个函数,这个函数在cores\arduino\Wiring_digital.c文件里。
void pinMode(uint8_t pin, uint8_t mode)
{
        uint8_t bit = digitalPinToBitMask(pin);
        uint8_t port = digitalPinToPort(pin);
        volatile uint8_t *reg, *out;

        if (port == NOT_A_PIN) return;

        // JWS: can I let the optimizer do this?
        reg = portModeRegister(port);
        out = portOutputRegister(port);
        ……
        ……
}

       我只贴出了主要功能函数,其它部分代码感兴趣的可以自己去研究。这里可以看出主要函数是digitalPinToBitMask,digitalPinToPort,portModeRegister,portOutputRegister这几个。本着打破砂锅问到底的精神,我们继续搜索这几个函数的实现,这下可以看到是4个宏。
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )

       对于pgm_read_byte这个函数我们就不用关心了,如果不知道的可以去问问万能的坛。关键的地方不是pgm_read_byte这个函数,而是pgm_read_byte这个函数里面的参数:digital_pin_to_port_PGM,digital_pin_to_bit_mask_PGM,pgm_read_word( port_to_input_PGM,pgm_read_word( port_to_mode_PGM。看看这四个参数的定义在哪里。
       经过搜索发现在Pins_arduino.h里,是不是很眼熟呀,是的,就是讲配置文件的时候讲过这个文件作用。
       所以不难发现,arduino是是先把各个芯片的端口和引脚的映射关系都定义成几个表格,这几个表格把引脚所在的位置作为索引,在使用的时候通过引脚位置,通过查表得到对应的功能寄存器。然后就可以设置输出输入模式,设置输入输出电平,对于arduino来说只需要告诉它需要操作哪个引脚,以及要怎么操作。而不需要去关心这个引脚在哪个port上,是在PORTA还是在PORTB,更不用关心这个芯片是什么型号。
       对于芯片的定时器,pwm等基础功能arduino都是按照这种方式实现的。就不再多说了。有了这些相信各位同学对arduino的使用会更加得心应手。
回复

使用道具 举报

发表于 2014-4-25 13:58:46 | 显示全部楼层
分析的透彻
回复 支持 反对

使用道具 举报

发表于 2014-9-29 16:32:44 | 显示全部楼层
对理解arduino很有用  赞一个
回复 支持 反对

使用道具 举报

发表于 2014-12-11 16:35:56 | 显示全部楼层
写的非常好,我不得不来顶一下。
回复 支持 反对

使用道具 举报

发表于 2014-12-16 12:31:45 | 显示全部楼层
谢谢指导
回复 支持 反对

使用道具 举报

发表于 2014-12-16 13:32:31 | 显示全部楼层
楼主的功力很深厚啊
回复 支持 反对

使用道具 举报

发表于 2016-4-28 15:57:57 | 显示全部楼层
汉化好好好好好好
回复 支持 反对

使用道具 举报

发表于 2016-4-28 19:05:04 | 显示全部楼层
太好了,继续更新,谢谢楼主
回复 支持 反对

使用道具 举报

发表于 2016-6-7 14:08:19 | 显示全部楼层
深入浅出,讲得很好理解,赞。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-27 08:05 , Processed in 0.039290 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表