在学习 GRBL 中,涉及到很多 AVR 中断、串口等相关知识。参考资料 MAKE:AVR PROGRAMMING
如果单独列出来,会减轻 学习 GRBL 的负担。
*************************
AVR 中断
*************************
064820grbjpinizr1rg9lu.jpg (24.99 KB, 下载次数: 78)
2016-4-9 23:57 上传
使用中断,而不是 polling (轮询方式),
One problem with polling in event loops is that there’s no concept of priority.
Handling multiple jobs at once is where interrupts excel.
Interrupts do just what they sound like—they interrupt the normal flow of the program.
When an interrupt is triggered, all of the variables that you’re using are stashed in memory and then a special function, called an interrupt service routine (ISRs), is run.
There are two flavors of external interrupts: the fancy interrupts, INT0 and INT1, and the pin-change interrupts.
065450g47qg6e72mj1e4ew.png (309.46 KB, 下载次数: 61)
2016-4-9 23:57 上传
The INT0 interrupt mechanism has more versatile triggering possibilities, allowing you trigger the interrupt on a rising voltage, a falling voltage, any change, or continuously for a low-voltage level.
there are only two of
these type interrupts: INT0 and INT1, on pins PD2 and PD3.
The PCINT system, on the other hand, allows you to treat every I/O pin on the AVR as an interrupt source if you so desire, but only detects changes (not their direction.
The pin-change interrupts are grouped together in banks, so it’s more accurate to say that there’s a pin-change interrupt for the “B” pins, one for the “C” pins, and one for the “D” pins.
We use pinmask registers to select which of the pins from within the bank we want to trigger the interrupt.
ISRs are special routines that run when their interrupt flag is set, and their interrupt vector is called.
这里,vector 表示 8位 无符号数,是地址。
070501u9bw5ycwiw6kli8t.jpg (17.33 KB, 下载次数: 87)
2016-4-9 23:57 上传
Pin-Change Interrupt Example
ISR(PCINT2_vect){
....
}
void initPinChangeInterrupt18(void){
PCICR |= (1 << PCIE2); /* set pin-change interrupt for D pins */
PCMSK2 |= (1 << PCINT18); /* set mask to look for PCINT18 / PD2 */
// PCMSK2 |= (1 << PD2); /* this will also work for the pin mask */
sei(); /* set (global) interrupt enable bit */
}
071405vcfzlyno7fn28fiy.jpg (12.66 KB, 下载次数: 93)
2016-4-9 23:57 上传
we’ll need to tell the AVR which pins we’d like for it to watch specifically.
This is done through the pin mask, which is just a normal 8-bit byte where the corresponding bit is set for each pin we’d like to be able to trigger the interrupt.
071640gi55z4l6vlvvgv6k.jpg (47.92 KB, 下载次数: 97)
2016-4-9 23:57 上传
So if we want to trigger on PD2 and PD4, we can set the pin mask one of two ways.
We can either use the pins’ PCINTxx aliases, or the normal PD2 type pin references.
For instance:
PCMSK2 |= ( (1 << PCINT18) | (1 << PCINT20) );
or
PCMSK2 |= ( (1 << PD2) | (1 << PD4) );
both do the same thing: configure the pin-change interrupt to trigger if either PD2 and PD4 changes state.
结论,3段式
071949irtlhv8vxxwutxts.jpg (72.52 KB, 下载次数: 82)
2016-4-9 23:57 上传
****************************
AVR 定时
*****************************
http://www.51hei.com/bbs/dpj-47869-1.html
使用定时器必须弄清的几个概念
在MCU中(M16),定时器是独立的一个模块,M16有三个独立的定时器模块,即T/C0、T/C1和T/C2;其中T/C0和T/C2都是8位的定时器,而T/C1是一个16位的定时器。定时器的工作是独立于CPU之外自行运行的硬件模块。
1、定时器何时开始工作(或说计数)的?
当TCCR0!=0x00任何模式下,只要MCU一上电,T/C就开始计时工作。其实TCCR0主要是定时器的预分频和波形模式、比较匹配模式的设置,说到预分频,不得不提一下这个模块,这个模块是T/C0、T/C1共用的一个模块,但可以有不同的分频设置。
2、定时器是如何进行工作的:说到定时器的工作,不得不说三个个重要参数:TCNT0、OCR0,TIMSK,TCNT0是设置定时器的计时初始值,定时器开始工作后立即从TCNT0一直累加到0XFF,累加过程所消耗的时间就是我们需要的定时时间;OCR0是一个比较设定值,当TCNT0的值累计到OCR0时(TNCT0==OCR0),如果有开启比较匹配中断功能,那么此时就会产生比较中断,所以,OCR0的值一般都是设置在TCNT0初始值和0XFF之间,之外的任何值都不会产生比较中断。TIMSK是一个中断使能位设置,就是我们需要计时器溢出中断或是比较匹配中断功能或两者都要时就对TIMSK的相应寄存器位进行设置。
3、定时器的中断使用,一个定时器可以有两个中断资源可利用,一个只溢出中断,另一个是比较匹配中断,如上面2所说的。想说明的溢出中断子程序内一般要有重载TCNT0的初始值,否则,TCNT0就会从0X00开始累加计数到0XFF,所耗费的时间就不我们想要的时间。比较中断就是当TCNT0==OCR0时,发生比较匹配中断;所以,中断子程序中一般只插入少量的处理代码,否则,会发生所谓的中断套嵌的现象,由于M16不支持中断套嵌,这样会使得中断子程序中的部分代码无法执行,严重时会造成系统崩溃。
4、TCNT0和OCR0的值换算:对于8bit的计时器,TCNT0一般可以由下面的公式换算:
TCNT0=256-(TV*F)/N;
TV: 所想要设定的定时时间,单位,us
F: 晶振频率(MHz)
N: 分频因子
void init_timer1()
{
//TCCR1A T/C1控制寄存器A
// -----------------------------------------------------------------
// | COM1A1| COM1A0| COM1B1| COM1B0| COM1C1| COM1C0| WGM11 | WGM10 |
// -----------------------------------------------------------------
//TCCR1B T/C1控制寄存器B
// -----------------------------------------------------------------
// | ICNC1 | ICES1 | - | WGM13 | WGM12 |CS12 |CS11 |CS10 |
// -----------------------------------------------------------------
//TCCR1C T/C1控制寄存器C
// -----------------------------------------------------------------
// | FOC1A | FOC1B | FOC1C | - | - | - | - | - |
// -----------------------------------------------------------------
// COM1A1,COM1A0:通道A的比较输出模式
// COM1B1,COM1B0:通道B的比较输出模式
// COM1C1,COM1C0:通道C的比较输出模式
// WGM13,WGM12,WGM11,WGM10:波型发生模式:
// 比较输出模式(CTC模式),非PWM
// 00普通端口操作,OC1A/OC1B/OC1C未连接
// 01比较匹配时OC1A/OC1B/OC1C电平取反
// 10比较匹配时清零OC1A/OC1B/OC1C(输出低电平)
// 11比较匹配时置位OC1A/OC1B/OC1C(输出高电平)
// 比较输出模式(CTC模式),快速PWM
// 00普通端口操作,OC1A/OC1B/OC1C未连接
// 01WGM13为0时同上,为1时 比较匹配时 OC1A电平取反,OC1B/OC1C保留
// 10比较匹配时OC1A/OC1B/OC1C清零,在TOP时OC1A/OC1B/OC1C置位
// 11比较匹配时OC1A/OC1B/OC1C置位,在TOP时OC1A/OC1B/OC1C清零
// 比较输出模式(CTC模式),相位修正及相频修正PWM
// 00普通端口操作,OC1A/OC1B/OC1C未连接
// 01WGM13为0:同上,为1时 比较匹配时 OC1A电平取反,OC1B/OC1C保留
// 10升序计数匹配时将OC1A/OC1B/OC1C清零,降序计数匹配时将OC1A/OC1B/OC1C置位
// 11升序计数匹配时将OC1A/OC1B/OC1C置位,降序计数匹配时将OC1A/OC1B/OC1C清零
//
// 模式 WGM1x 工作模式说明 TOP OCR1x更新时刻TOVn置位时刻
// 0 0000 普通模式 0xFFFF 立即 MAX
// 1 0001 8位相位修正PWM0x00FF TOP BOTTOM
// 2 0010 9位相位修正PWM0x01FF TOP BOTTOM
// 3 001110位相位修正PWM0x03FF TOP BOTTOM
// 4 0100 CTC OCRnA 立即 MAX
// 5 0101 8位快速PWM0x00FF TOP TOP
// 6 0110 9位快速PWM0x01FF TOP TOP
// 7 0111 10位快速PWM0x03FF TOP TOP
// 8 1000相位频率修正PWM ICRn BOTTOM BOTTOM
// 9 1001相位频率修正PWM OCRnA BOTTOM BOTTOM
// 10 1010 相位修正PWM ICRn TOP BOTTOM
// 11 1011 相位修正PWM OCRnA TOP BOTTOM
// 12 1100 CTC ICRn 立即 MAX
// 13 1101 保留 - - -
// 14 1110 快速PWM ICRn TOP TOP
// 15 1111 快速PWM OCRnA TOP TOP
// ICNC1:使能/禁止输入捕捉噪声抑制器
// ICES1:输入捕获触发沿选择,0为下降沿触发,1为上升沿触发
// CS12,CS11,CS10:T/C0时钟预分频选择
// 000:无时钟,T/C不工作 001:1/1
// 010:1/8 011:1/64 100:1/256
// 101:1/1024110:外部T1脚下降沿驱动 111:外部T1脚上升沿驱动
// FOC1A,FOC1B,FOC1C:强制输出比较通道A,B,C
TCCR1A = TCCR1B = TCCR1C = 0;
//TCNT1H,TCNT1L 定时/计数器1
//OCR1AH,OCR1AL 输出比较寄存器1A
//OCR1BH,OCR1BL 输出比较寄存器1B
//OCR1CH,OCR1CL 输出比较寄存器1C
//ICR1H,ICR1L 输入捕捉寄存器1
}
有个注意事项,
121331gr5bfwiffd8i3k8i.jpg (119.74 KB, 下载次数: 88)
2016-4-9 23:57 上传
看过很多实例代码,没有遵循上面的 位运算 ,都是 unreadable。