Arduino UNO의 I2C SCL 주파수를 극단적으로 낮추고 싶을 때
10983 단어 Arduino
Arduino UNO (ATmega328P)의 I2C 주변 장치를
Wire
라이브러리로 구동하는 경우 SCL 주파수는 Wire.setClock()
함수로 설정합니다. 설정하지 않을 경우의 디폴트값은 100 kHz이다.Arduino UNO(ATmega328P)의 SCL 주파수 SCLfreq는 데이터시트에 의하면
TWBR[7:0]
, TWSR[1:0]
SCLfreq = F_CPU/(16 + 2 * TWBR * 4^TWPS)
(
TWPS
는 0~255, TWBR
는 0~3)따라서 SCL 주파수는 (F_CPU/16) ~ (F_CPU/32656) 범위에서 설정할 수 있습니다. 그러나
TWPS
함수는 Wire.setClock()
가 TWSR[1:0]
에 고정되어 있으므로 (F_CPU/16) ~ (F_CPU/526)의 범위에서만 설정할 수 있다 (F_CPU = 16 MHz로 하면 SCLfreq = 1 약 30 kHz).분주비를 526보다 높게 하고 싶은 경우는
0b00
함수는 사용하지 않고 Wire.setClock()
Arduino UNO (ATmega328P)의 I2C SCL 주파수를 극단적으로 낮추고 싶을 때의 샘플
예를 들어 아래와 같이 원하는 SCL 주파수에서
TWBR[7:0]
값(= TWSR[1:0]
)과 TWPS
값을 구하여 설정한다. 이것으로 32656 분주(F_CPU = 16 MHz로 하면 SCLfreq = 약 490 Hz)까지 낮출 수 있다. 할 수 있다는 것만으로 그다지 의미는 없다.확인을 위한 샘플 파일(.ino)
set_SCL_freq.h를 포함하고
TWSR[1:0]
함수로 SCL 주파수를 설정합니다. 여기에서는 500 Hz로 설정해 본다.#include <Wire.h>
#include "set_SCL_freq.h" // これをインクルードする。
void setup() {
Wire.begin();
//Wire.setClock(100000UL);
set_SCL_Clock(16000000UL, 500); // 引数は(F_CPU, 所望のSCL周波数)
}
void loop() {
Wire.beginTransmission(8);
Wire.endTransmission();
delay(500);
}
헤더 파일
set_SCL_freq.h
#ifndef SET_SCL_FREQ_H
#define SET_SCL_FREQ_H
//#include <avr/io.h>
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define CONSTRAIN(val, min, max) (MIN((MAX((val), (min))), (max)))
#define SQUARE(a) ((a) * (a))
// TWSR[1:0]、TWBR[7:0]の各値から、F_CPUが何分周されるのかを求めるマクロ。
#define DIV_REG(twps, twbr) (((twbr) * (1 << ((twps) * 2)) + 8) * 2)
const uint8_t TWPS_MAX = 3;
const uint8_t TWBR_MAX = 255;
const uint16_t DIV_MIN = DIV_REG(0, 0); // 最小16分周まで可
const uint16_t DIV_MAX = DIV_REG(TWPS_MAX, TWBR_MAX); // 最大32656分周まで可
const uint16_t DIV_MAX0 = DIV_REG(0, TWBR_MAX); // 526。TWPS = 0のときの最大分周比。
const uint16_t DIV_MAX1 = DIV_REG(1, TWBR_MAX); // 2056。TWPS = 1のときの最大分周比。
const uint16_t DIV_MAX2 = DIV_REG(2, TWBR_MAX); // 8176。TWPS = 2のときの最大分周比。
// F_CPUと所望のSCL周波数との比を求める函数。
uint16_t calc_div(uint32_t f_cpu, uint32_t scl_freq){
uint32_t div = f_cpu / scl_freq;
return (uint16_t)(CONSTRAIN(div, DIV_MIN, DIV_MAX));
}
// TWSR[1:0] (=TWPS)の値を求める函数。
uint8_t calc_twps(uint16_t div){
uint8_t twps;
if (div <= DIV_MAX0){twps = 0;} // F_CPUとSCL周波数との比が ~ 526の場合
else if(div <= DIV_MAX1){twps = 1;} // F_CPUとSCL周波数との比が 528 ~ 2056の場合
else if(div <= DIV_MAX2){twps = 2;} // F_CPUとSCL周波数との比が2064 ~ 8176の場合
else {twps = 3;} // F_CPUとSCL周波数との比が8208 ~ の場合
return twps;
}
// TWBR[7:0]の値を求める函数。
uint8_t calc_twbr(uint32_t f_cpu, uint32_t scl_freq, uint8_t twps){
scl_freq = CONSTRAIN(scl_freq, f_cpu / DIV_MAX, f_cpu / DIV_MIN);
return (uint8_t)((f_cpu - (scl_freq * 16)) / ((scl_freq * SQUARE(1 << twps)) * 2));
}
// TWSR[1:0] (=TWPS)、TWBR[7:0]を書き換えるための函数。
void set_SCL_Clock(uint32_t f_cpu, uint32_t scl_freq){
uint16_t div = calc_div(f_cpu, scl_freq); // 所望の分周比を求めて、
uint8_t twps = calc_twps(div); // TWSR[1:0] (=TWPS)の値を求めて、
TWSR = (TWSR & ~0b11) | twps; // その値でTWSR[1:0]を書き換えて、
TWBR = calc_twbr(f_cpu, scl_freq, twps); // TWBRレジスタも書き換える。
}
#endif
실행 결과
SCL을 관측하고 있다.
Reference
이 문제에 관하여(Arduino UNO의 I2C SCL 주파수를 극단적으로 낮추고 싶을 때), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/cyq04000/items/e109334d98c714db0803텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)