單晶片lab7結報

tags: arduino
實驗日期 : 2021/11/18

上課教材

lab1

SPEC

不使用delay(),每2秒改變LED亮暗。
使用Timer1 Register、Output Compare A Match Interrupt中斷模式、CTC mode。

Timer內部暫存器原理

  • 範例 : 透過計數器和除頻數,計算1秒
DDRB = (1 << 5);  // set pin 13 OUTPUT

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
DDRB(The Port B Data Direction Register)從LSB數來第5位設為1,也就是OUTPUT。
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
ATmega328P的PB5設為OUTPUT,由上圖電路可知如果PB5=HIGH時,接在上面的diode順壓,因此會亮。

TCCR1A = 0;             // TCCR1A Reset

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
register全都設為0,代表Timer Mode為Normal。

TCCR1B = 0;             // TCCR1B Reset
TCCR1B |= (1 << CS12);  // 256 prescaler

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
CS12=1、CS11=0、CS10=0,代表除頻256。
16,000,000256=62,500

TCNT1 = 3036;  // preload timer (65536-62500)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
計數器從3036開始計數,一直數到65536,共62500個,因此每次數62500個時,由於CLK頻率是62,500Hz,因此即為1秒。

TIMSK1 |= (1 << TOIE1);  // enable timer overflow interrupt
interrupts();  // enable interrupts

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
當TOIE這個bit為1,代表啟動overflow interrupt。

ISR(TIMER1_OVF_vect) {  // interrupt

參考AVR Interrupt VectorsTIMER1_OVF_vect定義為Timer/Counter1 Overflow。

PORTB ^= (1 << 5);  // blink
A B O
0 0 0
0 1 1
1 0 1
1 1 0

在ISR裡面,假設一開始PORTB是1,與1做XOR會變為0,再與1做XOR又會變為0,如此0、1值不斷交替。

TCNT1 = 3036;       // preload timer
}

在ISR裡面,要將計數器歸回3036重新開始數。

實現方法

DDRB = (1 << 5);

根據datasheet P73與原理圖,設定PB5,也就是Ardunio Uno外部pin 13為OUTPUT。

TCCR1B |= (1 << CS12) | (1 << CS10);

根據datasheet P110,CS12=1CS11=0CS10=1,代表除頻1024。

16,000,0001,024=15,625

TCCR1B |= (1 << WGM12);

根據datasheet P109,WGM12=1WGM11=0WGM10=0代表Timer/Counter Mode是CTC。

TIMSK1 |= (1 << OCIE1A);

根據datasheet P112,OCIE1A=1激活Timer/Counter1 output compare A match interrupt。

TCNT1 = 0;

根據datasheet P113,TCNT1從0開始數。

OCR1A = 31250;

根據datasheet P109,在CTC模式OCR1A為TOP,也就是說TCNT1會數到31250並歸0重數。因此在每秒數15,625下,數31,250次,就代表2秒。

31,250 次15,625 Hz=2 s

ISR(TIMER1_COMPA_vect) {
    noInterrupts();
    PORTB ^= (1 << 5);  // blink
    interrupts();
}

在ISR裡面,使用XOR的特性使PB5在0、1之間切換。

lab2

SPEC

不使用delay(),顯示精度到毫秒的計時器在LCD螢幕上。

實現方法

lab1原理,為了要使精度能到毫秒

TCCR1B |= (1 << CS12) | (1 << CS10);

除頻1024。

16,000,0001,024=15,625

OCR1A = 15.625;

CTC mode的上限設為15.625。

15.625 次15,625 Hz=0.001 s=1 ms 可得至1毫秒精度。

lab3

SPEC

不使用delay(),使用超聲波模組,每秒測量一次距離,並顯示在多工七段顯示器上。

實現方法

lab1原理,每秒的間距即為除頻256、上限62500。

TCCR1B |= (1 << CS12);
OCR1A = 62500;

62500 次16,000,000256 Hz=1 s

lab4

SPEC

不使用analogRead(),讀取可變電阻之類比值,並在Serial port顯示出來。
使用ADMUX、ADCSRA及ADCH/L Register。

實現方法

setup()裡面先設定好以下參數

ADMUX |= (1 << REFS0);

根據datasheet P217,REFS1=0REFS0=1代表參考電壓設定為AVCC with external capacitor at AREF pin。

ADCSRA |= (1 << ADEN);

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
根據datasheet P218,ADEN=1代表啟動ADC。

ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

根據datasheet P218,ADPS2=1ADPS1=1ADPS0代表除頻128。


loop()內反覆執行以下副函式。

uint16_t ReadADC(uint8_t channel) {
    // modulo to lower 3 bits, so between 0-7
    // use a bit mask to keep the original lower 3 bits
    channel = channel & 0b00000111;
    ADMUX |= channel;

    // start conversion
    ADCSRA |= (1 << ADSC);
    // wait until conversion is finished
    while(ADCSRA & (1<<ADSC))
        return ADC;  //return data
}

根據datasheet P209,首先要了解First Conversion (Single Conversion Mode)。

根據datasheet P218,Analog Channel Selection Bits的選擇表為

MUX3..0 Single Ended Input
0000 ADC0
0001 ADC1
0010 ADC2
0011 ADC3
0100 ADC4
0101 ADC5
0110 ADC6
0111 ADC7

因此只有channel後3位才是有效值,如果要設定ADC1為類比輸入channel就要設為0b00000001,也可以使用ADMUX |= (1 << MUX0);

ADCSRA |= (1 << ADSC);

根據datasheet P218,ADSC=1開啟ADC Conversion。

while (bit_is_set(ADCSRA, ADSC))
// or while(ADCSRA & (1<<ADSC))
    return ADC;

當ADSC回到1代表結束ADC Conversion,根據datasheet P206的block diagram,最後回傳ADC(ADC Multiplexer Output)。

lab5

SPEC

不使用analogRead(), analogWrite()
藉由Timer1 Register中PWM模式,使用可變電阻調整LED之亮暗。

實現方法

analogRead()功能同lab4實現方法,而`analogRead()

TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << WGM13);
ICR1 = TOP;

根據datasheet P109,設定為mode 14(Fast PWM),TOP值為ICR1。

TCCR1A |= (1 << COM1B1);

根據datasheet P109,COM1B0=0COM1B1=1代表Clear OC1A/OC1B on compare match (set output to low level)。

OCR1B = constrain(ReadADC(1), 0, TOP);

在loop裡面限制ReadADC(1)只能在0與TOP值變化,如下圖只能在計數器這段區間變化,當OCR1B變大時,PWM在高電位的訊號變大,因此Duty Cycle變大,反之亦同。如此動態調節OCR1B的值去實現寫入PWM的動作analogWrite()

lab6

SPEC

使用timer.h,實作lab3功能。

實現方法

Timer.h函式庫解決使用delay()時,程式會停擺在那邊,無法再處裡其他動作,因此可以控制數個LED以不同頻率閃爍。 以下為函式庫內常用的指令

#include "Timer.h"  //引用Timer程式庫
Timer T; //建立計時器物件(T可以自訂名稱)
t.oscillate(腳位, 時間, 狀態); //設定多少毫秒切換一次狀態(HIGH or LOW)
t.every(時間, 函式); //設定固定時間,呼叫函示
t.update(); //在loop裡面會檢查更新計時器

因此我只需將lab3

  • setups內加上
t.every(1000, supersonic);

每隔1秒呼叫函式supersonic()

  • loop內加上
t.update();

不斷更新檢查。

課後習題

Question 1

Arduino上的ATmega328p所採用的是AVR架構;之後課程用到的STM32則是使用ARM架構,比較兩種架構的差別。

Answer 1

  • 微控制器不同的主流架構差別。
X 8051 PIC AVR ARM
總線寬度 標準內核為8位 8位/16位/32位 32分之8位 32位大多數也可用於64位
通信協議 UART, USART, SPI, I2C PIC, UART, USART, LIN, CAN, 乙太網, SPI, 12C UART, USART, LIN, 12C, 乙太網, SPI, I2C(專用AVR支持CAN,USB, 以太網) UART, USART, LIN, 12C, SPI, CAN, USB, 乙太網, I2C, DSP, SAI(串列音頻介面), IrDA
速度 12時鐘/指令周期 4時鐘/指令周期 1個時鐘/指令周期 1個時鐘/指令周期
記憶 ROM, SRAM, FLASH SRAM, FLASH 閃存, SRAM, EEPROM 閃存, SDRAM, EEPROM
ISA CLSC RISC的一些功能 RISC RISC
內存架構 馮諾依曼建築 哈佛建築 改性 改進的哈佛架構
能量消耗 平均
家庭 8051個變種 ARMv4.5.6.7和系列 PIC16, PIC17, PIC18, PIC24, PIC32 Tiny, Atmega, Xmega, 專用AVR
社區 廣大 很好 很好 廣大
生產廠家 Philips, Atmel, Slicon Labs ,Intel等 Microchip Atmel Apple, Nvidia, Qualcomm, Samsung等
成本與功能相比 非常低 平均 平均
其他功能 以其標準而聞名 廉價 便宜、高效 高速運轉
流行的微控制器 AT89C51. Psy51等 PIC18FXX8, PIC16F88X, PIC32MXX Atmega8,16,32, Arduino社區 Cortex-R系列(實時任務處理,主要應用領域包括汽車、相機、工業、醫學)、Cortex-M系列(最節能的嵌入式設備)、Cortex-A系列(以最佳功耗實現最高性能)
  • AVR架構與ARM架構差別
No. AVR ARM
01. AVR micro controller refers to Advanced Virtual RISC (AVR). ARM micro controller refers to Advanced RISC Micro-controller (ARM).
02. It has bus width of 8 bit or 32 bit. It has bus width of 32 bit and also available in 64 bit.
03. It uses ART, USART, SPI, I2C communication protocol. It uses SPI, CAN, Ethernet, I2S, DSP, SAI, UART, USART communication protocol.
04. Its speed is 1 clock per instruction cycle. Its speed is also 1 clock per instruction cycle.
05. Its manufacturer is Atmel company. Its manufacturer is Apple, Nvidia, Qualcomm, Samsung Electronics and TI etc.
06. It uses Flash, SRAM, EEPROM memory. It uses Flash, SDRAM, EEPROM memory.
07. Its family includes Tiny, Atmega, Xmega, special purpose AVR. Its family includes ARMv4, 5, 6, 7 and series.
08. It is cheap and effective. It provides high speed operation.
09. Popular micro-controllers include Atmega8, 16, 32, Arduino Community. Popular micro-controllers include LPC2148, ARM Cortex-M0 to ARM Cortex-M7, etc.

ARM是IP核,可供各大晶元商集成到各自的設計中,好比是軟體語言中的C++,如果你想換一家廠商或者某家的貨太貴,都會有其它的廠商來競爭,至少從理論上,你不會被一家廠商套住。AVR這方面就差點,ATMEL一家,別無分號。你只能在他的系列中選一個型號,無法選廠家。好比是軟體語言中的Java,雖然現在免費(指Java的SDK,不是AVR)或價格低,但市場前景更多的掌握在廠商手中。

實際產品成本方面,AVR優於ARM,畢竟AVR是8位機,配什麼外設都便宜,由於速度比ARM低,PCB版也好設計,20MHz的數字電路基本上只要通就行了,不用過多考慮信號完整性什麼的。而ARM的速度能輕易上100MIPS,32位的CPU也不是吹的,速度上AVR根本沒法比,不過帶來的問題就多了,要4層PCB,而且外設也貴多了。

功能方面,ARM大大優於AVR,ARM可以做手機,AVR顯然不行,但最大的優勢在ARM上可以跑Linux,Linux可以做很多事,在功能上的優勢意味著ARM比AVR有著更廣的應用範圍。

Question 2

分別描述在ATmega328p晶片上的PWM模式:Normal Mode, CTC Mode, Fast PWM Mode,及 Phase Correct PWM Mode。(Hint : 參考datasheet P79)

Answer 2

參照lab6 Question 2

模式 TCNT計數器
Normal 從0數到overflow,並進入ISR裡面處理 - 歸0重數。
CTC
Fast PWM
Phase-correct PWM

心得

劉永勝

這次實驗並不是直接呼叫arduino的函式或巨集,而是直接更改ATmega328p的register,藉由更改register所存取的位元,執行晶片的功能。相較於現成函式,這樣更改register的方式相當麻煩,須先設定enable、mode等,才能寫入值。但也因為直接改寫暫存器的值,能更了解此晶片的功能。但這不是3hr就能理解的。

李宇洋

此次實驗要直接使用Arduino上的ATmega328p做操作,因為實驗的內容主要是對硬體原本所配置的暫存器在IDE上直接操作,觸發中斷程序以作為Timer使用,所以需要直接查詢晶片在datasheet上製作時的設定。有一部分Code雖然助教都已經幫忙打好了,但是要在4、5個小時內理解各個暫存器還有裡面的各個bits負責的功能真的有點困難。

陳旭祺

前面幾周都是調用別人寫好的函式庫,去實現我們需要的功能,但這次lab開始深入探討並直接操作硬體的register,這部分需要具備看datasheet與分析電路圖的能力。前者偏向Arduino社群的業餘玩家,只需要使用別人寫好的函式庫,不需要搞懂硬體底層,就能快速實作出想要的功能,很有成就感;後者偏向嵌入式開發所探討的硬體底層,我們光是實現一個delay()功能就研究不少時間,較沒有成就感。

lab1-lab3為實現delay()功能,使用Timer的CTC mode、lab4-lab5實現analogRead(),analogWrite(),讀入類比值使用Single Conversion Mode,而寫出類比值,藉由動態改變Fast PWM下OCR1B的值,去影響PWM的duty cycle。