上一篇我们分析了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