Arduino引脚读PWM信号???
我把Arduino的3号引脚和A0引脚用线连接起来,然后编写下面的程序,就是让3号引脚发出模拟电压,用A0号引脚读入,为什么会读不出呢?另:
我买了一个绝对编码器,编码器的引脚是这样的:
红色:3.3V
黑色:GND
黄色:CSN
绿色:CLK
蓝色:D0
白色:PWM
我尝试用Arduino的A0引脚来读取PWM的值,结果也读不出!
电路图如图:
结果如图:
我觉得我的两个问题是一致的,为什么会读不出值呢???哪里出问题了???我觉得是接线的问题!!! 本帖最后由 275891381 于 2016-11-17 22:00 编辑
肯定不行呀,至少弄个积分电路吧 把pwm转成模拟量
,
读编码器要用中断 楼上正解,PWM 属于脉宽调制输出,ArduinoPWM其输出的电压量依然是0V 和5V,只是通过脉冲不同的占空比来改变输出的功率。
另外,你的编码器用的3.3V电压,编码器输出的脉冲也是3.3V和0V的脉冲,自然得到的是660 (1024/5 *3.3)当然,会有一点误差。
实际这两种模块输出的都是非连续变化的脉冲。所以可以用用旋钮电阻。 如果只是要讀取 PWM 信號,直接使用計時器計數 PWM 的脈衝寬度會不會比較容易一點 275891381 发表于 2016-11-17 21:00
肯定不行呀,至少弄个积分电路吧 把pwm转成模拟量
,
事实上在用A0引脚读PWM脉冲之前,我就是尝试用中断来读PWM信号的!
由于我着急,匆忙,以为编码器不同的角度对应PWM信号的不同频率,所以我参考“AVR单片机嵌入式系统原理与应用实践.pdf”第11章的例子,编写了程序,是读频率信号的频率的,其原理如下:
1. 使用两个定时计数器。T/C0工作在计数器方式,对外部T0引脚输入的脉冲信号计数(上升沿触发)。
2. T/C2工作在CTC方式,每隔1ms中断一次,每一次T/C2的中断中,都首先记录下T/C0寄存器TCNT0当前的计数值,因此前后两次TCNT0的差值(time0_new - time0_old)或(256 - time0_old + time0_new)就是1ms时间内T0脚输入的的脉冲个数(这个表达式要理解,其原理是溢出了,超过了256)。为了提高测量精度,程序对100个1ms的脉冲个数进行了累计(在变量freq中),即已知限定的时间为100ms。
下面是我的程序:
unsigned int time_1ms_ok;
unsigned int time0_old, time0_new, freq_time;
unsigned long freq;
void setup() {
// 初始化
freq = 0;
freq_time = 0;
time_1ms_ok = 0;
time0_old = 0;
DDRD = 0x00;// 端口PD4的第二功能,T/C0外部计数器输入
TCCR0A = 0;
TCCR0B = 1 << CS02 | 1 << CS01 | 0 << CS00; // 外部T0引脚下降沿触发计数,普通模式;
//TCNT0 = 0x00; // 初始化计数值
TCCR2A = 1 << WGM21;
TCCR2B = 1 << CS22; // 内部时钟,64分频(16M/64 = 0.25MHz),CTC模式
TCNT2 = 0x00; // 初始化计数值
/*
0.25MHz/1000Hz = 250
*/
OCR2A = 0xF9;// OCR2 = 0xF9(249) ,(249+1)*(1/0.25MHz) = 1ms
TIMSK2 = 1 << OCIE2A;// 允许T/C2比较匹配中断
TIFR2 = 1 << OCF2A;
Serial.begin(9600);
}
void loop() {
if (time_1ms_ok)
{
if (time0_new >= time0_old)
freq = freq + (time0_new - time0_old);
else
freq = freq + (256 - time0_old + time0_new);
time0_old = time0_new;
freq_time += 1;
if (freq_time >= 100)
{
// 显示计数值
Serial.println(freq);
freq_time = 0; // 100ms到
freq = 0;
}
time_1ms_ok = 0;
}
}
// 中断
ISR(TIMER2_COMPA_vect)
{
time0_new = TCNT0;// 1ms到,记录当前T/C0的计数值
time_1ms_ok = 1;
}
但后来我发现,这个程序只能读出PWM信号的频率,但以我的理解,绝对编码器的不同角度,对应不同的PWM信号占空比,所以光读频率还不行,得读占空比,对不?
如果是这样的话,问题就来了:在上面这个读频率的程序中,第1步要求把T/C0设置为上升沿计数还是下降沿计数,可如果要读PWM的占空比,需要既读上升沿、又要读下降沿,这可怎么设置呢??? croma 发表于 2016-11-18 10:33
如果只是要讀取 PWM 信號,直接使用計時器計數 PWM 的脈衝寬度會不會比較容易一點
您能给我提供一个都PWM信号占空比的编程思路么?
事实上在用A0引脚读PWM脉冲之前,我就是尝试用中断来读PWM信号的!
由于我着急,匆忙,以为编码器不同的角度对应PWM信号的不同频率,所以我参考“AVR单片机嵌入式系统原理与应用实践.pdf”第11章的例子,编写了程序,是读频率信号的频率的,其原理如下:
1. 使用两个定时计数器。T/C0工作在计数器方式,对外部T0引脚输入的脉冲信号计数(上升沿触发)。
2. T/C2工作在CTC方式,每隔1ms中断一次,每一次T/C2的中断中,都首先记录下T/C0寄存器TCNT0当前的计数值,因此前后两次TCNT0的差值(time0_new - time0_old)或(256 - time0_old + time0_new)就是1ms时间内T0脚输入的的脉冲个数(这个表达式要理解,其原理是溢出了,超过了256)。为了提高测量精度,程序对100个1ms的脉冲个数进行了累计(在变量freq中),即已知限定的时间为100ms。
下面是我的程序:
unsigned int time_1ms_ok;
unsigned int time0_old, time0_new, freq_time;
unsigned long freq;
void setup() {
// 初始化
freq = 0;
freq_time = 0;
time_1ms_ok = 0;
time0_old = 0;
DDRD = 0x00;// 端口PD4的第二功能,T/C0外部计数器输入
TCCR0A = 0;
TCCR0B = 1 << CS02 | 1 << CS01 | 0 << CS00; // 外部T0引脚下降沿触发计数,普通模式;
//TCNT0 = 0x00; // 初始化计数值
TCCR2A = 1 << WGM21;
TCCR2B = 1 << CS22; // 内部时钟,64分频(16M/64 = 0.25MHz),CTC模式
TCNT2 = 0x00; // 初始化计数值
/*
0.25MHz/1000Hz = 250
*/
OCR2A = 0xF9;// OCR2 = 0xF9(249) ,(249+1)*(1/0.25MHz) = 1ms
TIMSK2 = 1 << OCIE2A;// 允许T/C2比较匹配中断
TIFR2 = 1 << OCF2A;
Serial.begin(9600);
}
void loop() {
if (time_1ms_ok)
{
if (time0_new >= time0_old)
freq = freq + (time0_new - time0_old);
else
freq = freq + (256 - time0_old + time0_new);
time0_old = time0_new;
freq_time += 1;
if (freq_time >= 100)
{
// 显示计数值
Serial.println(freq);
freq_time = 0; // 100ms到
freq = 0;
}
time_1ms_ok = 0;
}
}
// 中断
ISR(TIMER2_COMPA_vect)
{
time0_new = TCNT0;// 1ms到,记录当前T/C0的计数值
time_1ms_ok = 1;
}
但后来我发现,这个程序只能读出PWM信号的频率,但以我的理解,绝对编码器的不同角度,对应不同的PWM信号占空比,所以光读频率还不行,得读占空比,对不?
如果是这样的话,问题就来了:在上面这个读频率的程序中,第1步要求把T/C0设置为上升沿计数还是下降沿计数,可如果要读PWM的占空比,需要既读上升沿、又要读下降沿,这可怎么设置呢??? 本帖最后由 croma 于 2016-11-18 17:13 编辑
如果不在乎資源的消耗的話 最容易實現的方式
假設以 1 Byte 表示 PWM 信號 也就有 256 個狀態 取 250 個來表示
PWM 信號的週期如果為 25ms 除以 250 每一個變化是 100us
那麼設定一個計時器每 100us 去檢查一次這個 PWM 信號
當由零變一時歸零 計數值 每次檢查信號為一時 計數值遞增 直到一變零的那一刻就根據計數值去刷新 PWM 值
不清楚你用的哪款绝对型编码器,绝对型编码器读的是相位差,或者光栅码。一般舵机上用的是质量好一些的旋转电阻器。
另外,你一开始的问题比较模糊,容易给人误解,反而不能更好的帮你。
用外部中断,触发方式改成边沿触发,加上定时器计时。这样能算出脉宽和频率,但还是我说的,不太清楚你需要干什么。 本帖最后由 liangquan 于 2016-11-18 19:29 编辑
164335413 发表于 2016-11-18 19:02
不清楚你用的哪款绝对型编码器,绝对型编码器读的是相位差,或者光栅码。一般舵机上用的是质量好一些的旋转 ...
用的是这款编码器。
https://item.taobao.com/item.htm?spm=a1z09.2.0.0.TlHVwH&id=532121303239&_u=iiluasi7341
它有两种输出信号形式:
SSI信号(CSN、CLK、DO三根信号线)、PWM(一根信号线)
前一个不会用,稍明白点后一个,所以想读PWM信号,获得角度值。
就是想读编码器的输出信号,获得角度值。应该怎样读这个PWM信号?
如图所示,不是要么上升沿、要么下降沿,也没有边沿触发呀? 本帖最后由 croma 于 2016-11-18 20:51 编辑
liangquan 发表于 2016-11-18 19:16
用的是这款编码器。
https://item.taobao.com/item.htm?spm=a1z09.2.0.0.TlHVwH&id=532121303239&_u=i ...
如果你的接腳有餘裕的話~ 我建議你還是讀SSI 信號吧~ 比較簡單 精度也比較高
PWM 信號要得到同樣解析度的成本要高得多了
產品上有附給你 SSI 的時序圖了
三線
CSn <- 致能
CLK <- 時脈
D0<- 資料
CSn 和 CLK 先送高電位 1us
CSn 送 低電位 1us
接下來 CLK 間隔 1us 送 10 個正負變化
在 CLK 發送 負源 信號的時候 從 D0 收取一個 bit 的資料 每收一個位元就左移一位
這部分是角度資料解析度是 1024
接下來 CLK 間隔 1us 送 6 個正負變化
在 CLK 發送 負源 信號的時候 從 D0 收取一個 bit 的資料 每收一個位元就左移一位
這部分是狀態字和同位符號
liangquan 发表于 2016-11-18 19:16
用的是这款编码器。
https://item.taobao.com/item.htm?spm=a1z09.2.0.0.TlHVwH&id=532121303239&_u=i ...
如果你非要透過中斷觸發,那就把 pwm 信號連到兩個中斷上,一個處理正緣 啟動 16 bit 的計時器順便計算週期,另一個處理負緣抓 pwm 的時間 谢谢,深受启发
页:
[1]