新建一个Arduino程序。可是建完就郁闷了,因为只看到了setup和loop函数,却没有基本的c函数。
从配置文件来看,核心代码在cores\arduino下。进入代码目录可以看到这里各个文件都是按照功能来命名的,所以很好辨认。很容易就能找到main.cpp,我们打开来看看具体内容:
看到我们熟悉的main函数了吧,同时看到main函数里在初始化时调用了setup函数,在for循环里调用了loop函数,所以这下大家明白了为什么在arduino中写代码的时候只看到setup和loop函数了吧,setup函数和loop函数已经预调用了。
接下来再打开一个最简单的例子Blink。
这个代码原理很简单,把引脚13设置成输出,然后使用for循环,在13脚交替输出高低电平;这个逻辑很好理解。但是这其中又有疑问了;写过avr c代码的同学肯定都知道,一般对某个端口或者引脚操作都是使用DDRX,PORTX,PINX来操作的,为什么这里可以直接用数字来操作呢?
接下来继续分析一下pinMode这个函数,这个函数在cores\arduino\Wiring_digital.c文件里。
我只贴出了主要功能函数,其它部分代码感兴趣的可以自己去研究。这里可以看出主要函数是digitalPinToBitMask,digitalPinToPort,portModeRegister,portOutputRegister这几个。本着打破砂锅问到底的精神,我们继续搜索这几个函数的实现,这下可以看到是4个宏。
本文的关键,不是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。看看这四个参数的定义在哪里。
对于芯片的定时器,pwm等基础功能arduino都是按照这种方式实现的。就不再多说了。有了这些相信各位同学对arduino的使用会更加得心应手。
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();
#endifsetup();for (;;) {loop();if (serialEventRun) serialEventRun();}return 0;
}
看到我们熟悉的main函数了吧,同时看到main函数里在初始化时调用了setup函数,在for循环里调用了loop函数,所以这下大家明白了为什么在arduino中写代码的时候只看到setup和loop函数了吧,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 seconddigitalWrite(led, LOW); // turn the LED off by making the voltage LOWdelay(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_xxx宏定义其实就是一段包括了flash读取指令的内联汇编代码。函数原型为:
pgm_read_byte(address_short);pgm_read_word(address_short);pgm_read_dword(address_short);pgm_read_float(address_short);//括号中是地址值。
本文的关键,不是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。看看这四个参数的定义在哪里。
经过搜索发现在 hardware\arduino\variants\leonardo\ Pins_arduino.h里,是不是很眼熟呀,是的,就是讲配置文件的时候讲过这个文件作用。
对于芯片的定时器,pwm等基础功能arduino都是按照这种方式实现的。就不再多说了。有了这些相信各位同学对arduino的使用会更加得心应手。