Grbl源码解析与移植-IO寄存器与中断

上一篇我们分析了system.c,它除了执行系统命令外,还处理了其他功能例如:安全门,重置,暂停,恢复等功能,这就涉及到对IO引脚的操作了,Grbl中直接使用寄存器操作IO引脚

,为什么要直接使用寄存器操作IO呢?因为端口寄存器允许更低级和更快地操纵IO引脚

还可以使得它控制的引脚输出更加同步。如果单独实现某一个输出引脚的值,就需要执行多次才能完成多个轴的运动,这会产生阶梯状锯齿运动轨迹,这在CNC中是不允许的。下面我们详细分析IO映射和操作。

在开始IO操作前,我们先看一张图:


Atmega328p有三个端口(途中黑框标注):

B:数字引脚8到13

C:模拟输入引脚

D:数字引脚0到7

每个端口由3个寄存器控制:

DDR:Data Direction Register 控制引脚是INPUT还是OUTPUT

PORT: 控制引脚是高电平还是低电平

PIN: INPUT引脚的状态,只读

我们以其中一个端口D为例:

DDRD - 端口D数据方向寄存器 - 读/写

PORTD - 端口D数据寄存器 - 读/写

PIND - 端口D输入引脚寄存器 - 只读

DDRD = DDRD | B11111100; //将Arduino引脚1至7设置为输出,将引脚0设置为输入 ,这样更安全,因为它将引脚2到7设置为输出 ,不改变引脚0和1的值,即RX和TX

PORTD = B10101000; // 设置数字7,5,3引脚为高电平

弄清楚了IO端口寄存器的使用,我们结合Grbl中的代码来分析:

// 定义用户控制的输入引脚(启动循环,重置,进给保持)

// 注意:所有控制引脚必须在同一端口,并且不能覆盖其他引脚定义(如限位开关)

// Define user-control controls (cycle start, reset, feed hold) input pins.

// NOTE: All CONTROLs pins must be on the same port and not on a port with other input pins (limits).

#define CONTROL_DDR DDRC

#define CONTROL_PIN PINC

#define CONTROL_PORT PORTC

#define CONTROL_RESET_BIT 0 // Uno Analog Pin 0

#define CONTROL_FEED_HOLD_BIT 1 // Uno Analog Pin 1

#define CONTROL_CYCLE_START_BIT 2 // Uno Analog Pin 2

#define CONTROL_SAFETY_DOOR_BIT 1 // Uno Analog Pin 1 NOTE: Safety door is shared with feed hold. Enabled by config define.

#define CONTROL_INT PCIE1 // Pin change interrupt enable pin 引脚变化使能

#define CONTROL_INT_vect PCINT1_vect // 引脚变化中断向量

#define CONTROL_PCMSK PCMSK1 // Pin change interrupt register 引脚变化中断寄存器

#define CONTROL_MASK ((1<<CONTROL_RESET_BIT)|(1<<CONTROL_FEED_HOLD_BIT)|(1<<CONTROL_CYCLE_START_BIT)|(1<<CONTROL_SAFETY_DOOR_BIT))

#define CONTROL_INVERT_MASK CONTROL_MASK // May be re-defined to only invert certain control pins. 可能充定义为仅反转确定的引脚

这里定义了端口C作为输入控制用的一些引脚,他们和对刀,限位使用了同一端口,重定义这些引脚要小心,防止覆盖。然后还定义了功能位对应的掩码,方便编程时的操作。其他的是一些别名。

void system_init()

{

// 配置作为输入引脚

CONTROL_DDR &= ~(CONTROL_MASK); // Configure as input pins

#ifdef DISABLE_CONTROL_PIN_PULL_UP

// 如果禁用了内置的上拉使用低电平有效操作,则需要外部接下拉电阻

CONTROL_PORT &= ~(CONTROL_MASK); // Normal low operation. Requires external pull-down.

#else

// 如果使用内置上拉电阻,则高电平有效

CONTROL_PORT |= CONTROL_MASK; // Enable internal pull-up resistors. Normal high operation.

#endif

// 开启指定引脚变化的中断

CONTROL_PCMSK |= CONTROL_MASK; // Enable specific pins of the Pin Change Interrupt

// 使能引脚变化

PCICR |= (1 << CONTROL_INT); // Enable Pin Change Interrupt

}

// 引脚变化中断处理,例如启动循环,进给保持,重置等。

// 只设置实时命令执行变量以便主程序中执行他们。

// 这精确的执行从串口流直接捡取的类似基于字符的实时命令。

// Pin change interrupt for pin-out commands, i.e. cycle start, feed hold, and reset. Sets

// only the realtime command execute variable to have the main program execute these when

// its ready. This works exactly like the character-based realtime commands when picked off

// directly from the incoming serial data stream.

ISR(CONTROL_INT_vect)

{

uint8_t pin = system_control_get_state();

if (pin) {

if (bit_istrue(pin,CONTROL_PIN_INDEX_RESET)) {

mc_reset();

}

if (bit_istrue(pin,CONTROL_PIN_INDEX_CYCLE_START)) {

bit_true(sys_rt_exec_state, EXEC_CYCLE_START);

}

#ifndef ENABLE_SAFETY_DOOR_INPUT_PIN

if (bit_istrue(pin,CONTROL_PIN_INDEX_FEED_HOLD)) {

bit_true(sys_rt_exec_state, EXEC_FEED_HOLD);

#else

if (bit_istrue(pin,CONTROL_PIN_INDEX_SAFETY_DOOR)) {

bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);

#endif

}

}

}

配置好这些引脚作为相应的输入功能,在引脚变化时就会触发中断处理函数,中断处理函数

中仅改变一些实时命令变量的值,主程序会根据这些变量去执行。

作者:任羽飞2222

https://www.bilibili.com/read/cv11216347

出处: bilibili

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容