极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 7195|回复: 3

Arduino机械坊学习笔记04 补充资料( AVR 中断、串口等知识)_2014_3_23

  [复制链接]
发表于 2014-3-23 07:20:09 | 显示全部楼层 |阅读模式
在学习 GRBL 中,涉及到很多 AVR 中断、串口等相关知识。参考资料 MAKE:AVR PROGRAMMING

如果单独列出来,会减轻 学习 GRBL 的负担。

*************************
AVR 中断

*************************


19.jpg

使用中断,而不是 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.

atmega328w.png

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位 无符号数,是地址。

20.JPG


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 */
}

18.JPG

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.

21.JPG

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段式

22.JPG


回复

使用道具 举报

发表于 2014-3-23 21:58:58 | 显示全部楼层
如果只是觉得interrupt不够用的,可以考虑PinChangeInt.h
http://playground.arduino.cc/Main/PinChangeInt#.Uy7nZa2SzEQ
有兴趣下次写个简单介绍
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-3-24 08:33:44 | 显示全部楼层
Be1ieve 发表于 2014-3-23 21:58
如果只是觉得interrupt不够用的,可以考虑PinChangeInt.h
http://playground.arduino.cc/Main/PinChangeIn ...

谢谢提醒,感觉 PinChangeInt.h 应该会有用。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-3-29 12:19:26 | 显示全部楼层
Be1ieve 发表于 2014-3-23 21:58
如果只是觉得interrupt不够用的,可以考虑PinChangeInt.h
http://playground.arduino.cc/Main/PinChangeIn ...

****************************
AVR 定时

*****************************

http://blog.sina.com.cn/s/blog_7880f98301011k8b.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

}

有个注意事项,
27.JPG

看过很多实例代码,没有遵循上面的 位运算 ,都是 unreadable。
回复 支持 反对

使用道具 举报

高级模式  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2018-9-24 08:12 , Processed in 0.237903 second(s), 10 queries , File On.

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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