极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 22594|回复: 6

Arduino 怎么使用定时器产生 微妙级的中断

[复制链接]
发表于 2015-6-18 16:14:03 | 显示全部楼层 |阅读模式
想通过 IO 口定时器模拟出 PWM 波,但现在所知定时器只有毫秒级的,想产生 500HZ 的方波。。
回复

使用道具 举报

发表于 2015-6-19 08:09:17 | 显示全部楼层
本帖最后由 幻生幻灭 于 2015-6-19 08:16 编辑

之前做过一个方波发生器,参考下

  1. // Set CS10&CS11 bit for 64 prescaler
  2. //  OCR1A = 255;
  3. //Pe = 2, pu = 1 cycle about 2 ms freq = 490Hz
  4. //Pe = 4, pu = 2 cycle about 4 ms freq = 247Hz
  5. //Pe = 6, pu = 3 cycle about 6 ms freq = 165Hz
  6. //Pe = 7, pu = 4 cycle about 7 ms freq = 140Hz
  7. //Pe = 8, pu = 4 cycle about 8 ms freq = 125Hz
  8. //  OCR1A = 30;
  9. //Pe = 2, pu = 1 cycle about 0.1 ms freq = 4.03kHz
  10. //Pe = 4, pu = 2 cycle about 0.5 ms freq = 2.00kHz
  11. //Pe = 6, pu = 3 cycle about 0.8 ms freq = 1.35kHz
  12. //Pe = 8, pu = 4 cycle about 1 ms freq = 1.00kHz
  13. //  OCR1A = 25;
  14. //Pe = 2, pu = 1 cycle about 0.2 ms freq = 4.83kHz
  15. //Pe = 10, pu = 5 cycle about 1 ms freq = 960Hz
  16. //Pe = 23, pu = 11 cycle about 2.2 ms freq = 420Hz
  17. //Pe = 40, pu = 20 cycle about 4 ms freq = 244Hz(****)
  18. //Pe = 50, pu = 25 cycle about 5.2 ms freq = 193Hz
  19. //Pe = 100, pu = 50 cycle about 10 ms freq = 100Hz
  20. //Pe = 1000, pu = 500 cycle about 100 ms freq = 9.7Hz
  21. //Pe = 2000, pu = 1000 cycle about 200 ms freq = 5Hz
  22. //Pe = 5000, pu = 2500 cycle about 510 ms freq = 1.9Hz(****)

  23. //Hardware connection
  24. //R10Kx2 + 1.5K
  25. //R20K(电位器) +1.5K
  26. //Measure Range: 4.651V(0 - 950)
  27. //Period Range: 40 - 5000
  28. //Calculation: Period = 40 + A0*5(Range: 40 - 4790)
  29. //Calculation: PulseWidth = int((A1/950)*period)

  30. //Hardware Define
  31. int pinFreq = A2;
  32. int pinPulseWidth = A1;
  33. int pinFreqR = A3;
  34. int pinPulseWidthR = A0;
  35. int pinLed = 3;
  36. int pinPWM = 4;
  37. int pinKey = 5;
  38. int pinKeyV = 6;
  39. int pinKeyG = 7;
  40. int pinKeyVisu = 13;
  41. //variables for PW pot monitoring
  42. float pulseWidth;
  43. int pulseWidthScaled;
  44. int PWCurrent;
  45. byte PWTolerance = 2;//adjust this to increase/decrease stability of PW measurement

  46. //variables for freq pot monitoring
  47. int frequency;
  48. int freqCurrent;
  49. byte freqTolerance = 2;//adjust this to increase/decrease stability of frequency measurement
  50. unsigned int freqscaled;

  51. int t;
  52. int period;

  53. int testMode = 0; //Default is 0;
  54. int freqPreTest;
  55. int PWPreTest;
  56. //int cycleISR = 4; //unit us
  57. //定义一个comdata字符串变量,赋初值为空值
  58. String comdata = "";
  59. //numdata是分拆之后的数字数组
  60. int numdata[2] = {
  61.   0};
  62. int mark = 0;

  63. void setup() {
  64.   Serial.begin(9600);
  65.   //set port/pin  mode
  66.   pinMode(pinLed, OUTPUT);   
  67.   pinMode(pinPWM, OUTPUT);
  68.   pinMode(pinKeyV, OUTPUT);
  69.   pinMode(pinKeyG, OUTPUT);
  70.   pinMode(pinKeyVisu, OUTPUT);
  71.   pinMode(pinKey, INPUT);
  72.   digitalWrite(pinKeyV, HIGH);
  73.   digitalWrite(pinKeyG, LOW);
  74.   digitalWrite(pinKeyVisu, LOW);


  75.   //TIMER INTERRUPT SETUP
  76.   cli();//disable interrupts
  77.   //timer 1:
  78.   TCCR1A = 0;// set entire TCCR1A register to 0
  79.   TCCR1B = 0;// same for TCCR1B
  80.   //set compare match register- 100khz to start
  81.   OCR1A = 25; //period = 0.1ms
  82.   //turn on CTC mode
  83.   TCCR1B |= (1 << WGM12);
  84.   // Set CS10&CS11 bit for 64 prescaler
  85.   TCCR1B |= (1 << CS10) | (1 << CS11);
  86.   // enable timer compare interrupt
  87.   TIMSK1 |= (1 << OCIE1A);

  88.   //initialize variables 200Hz
  89.   t = 0;
  90.   period = 48;
  91.   pulseWidthScaled = 24;

  92.   sei();//enable interrupts

  93.   if(testMode == 1){
  94.     Serial.println(" ");
  95.     Serial.println("Test Mode Actived!");
  96.   }
  97. }


  98. //Leo checked
  99. ISR(TIMER1_COMPA_vect){//timer 1 interrupt
  100.   //increment t and reset each time it reaches period
  101.   t += 1;
  102.   if (t >= period){
  103.     t = 0;
  104.   }
  105.   if (pulseWidthScaled <= t) {
  106.     //PORTD = 0xff;
  107.     digitalWrite(pinPWM, HIGH);
  108.     digitalWrite(pinLed, HIGH);
  109.   }
  110.   else{
  111.     //PORTD = 0x00;
  112.     digitalWrite(pinPWM, LOW);  
  113.     digitalWrite(pinLed, LOW);  
  114.   }
  115. }

  116. //Leo checked
  117. void loop() {
  118.   if(testMode == 1) SerialInput();
  119.   checkFreq();
  120.   checkPW();
  121.   if(digitalRead(pinKey) == HIGH){
  122.     digitalWrite(pinKeyVisu, HIGH);
  123.   }
  124.   else{
  125.     digitalWrite(pinKeyVisu, LOW);
  126.   }
  127. }

  128. //Leo checked
  129. void checkFreq() {
  130.   if(digitalRead(pinKey) == HIGH){
  131.     freqCurrent = analogRead(pinFreq);
  132.   }
  133.   else{
  134.     freqCurrent = analogRead(pinFreqR);
  135.   }
  136.   if(testMode == 1) freqCurrent = freqPreTest;
  137.   if (abs(freqCurrent-frequency)>freqTolerance){//if reading from pot exceeds tolerance
  138.     frequency = freqCurrent;
  139.     period = 40 + frequency*5; //Range: 40 - 4790
  140.   }
  141. }

  142. //Leo checked
  143. void checkPW() {
  144.   if(digitalRead(pinKey) == HIGH){
  145.     PWCurrent = analogRead(pinPulseWidth);
  146.   }
  147.   else{
  148.     PWCurrent = analogRead(pinPulseWidthR);
  149.   }
  150.   if(testMode == 1) PWCurrent = PWPreTest;
  151.   if (abs(PWCurrent-pulseWidth)>PWTolerance){//if reading from pot exceeds tolerance
  152.     pulseWidth = PWCurrent;//new pulse width, val between 0 and 1023
  153.     if(digitalRead(pinKey) == HIGH){
  154.       pulseWidthScaled = int((pulseWidth/930)*period);
  155.     }
  156.     else{
  157.       pulseWidthScaled = int((pulseWidth/1023)*period);
  158.     }
  159.   }
  160. }

  161. //Leo checked
  162. void SerialInput(){
  163.   //j是分拆之后数字数组的位置记数
  164.   int j = 0;

  165.   //不断循环检测串口缓存,一个个读入字符串,
  166.   while (Serial.available() > 0)
  167.   {
  168.     //读入之后将字符串,串接到comdata上面。
  169.     comdata += char(Serial.read());
  170.     //延时一会,让串口缓存准备好下一个数字,不延时会导致数据丢失,
  171.     delay(2);
  172.     //标记串口读过数据,如果没有数据的话,直接不执行这个while了。
  173.     mark = 1;
  174.   }

  175.   if(mark == 1)  //如果接收到数据则执行comdata分析操作,否则什么都不做。
  176.   {
  177.     //显示刚才输入的字符串(可选语句)
  178.     //Serial.println(comdata);
  179.     //显示刚才输入的字符串长度(可选语句)
  180.     //Serial.println(comdata.length());

  181.     /*******************下面是重点*******************/
  182.     //以串口读取字符串长度循环,
  183.     for(int i = 0; i < comdata.length() ; i++)
  184.     {
  185.       //逐个分析comdata[i]字符串的文字,如果碰到文字是分隔符(这里选择逗号分割)则将结果数组位置下移一位
  186.       //即比如11,22,33,55开始的11记到numdata[0];碰到逗号就j等于1了,
  187.       //再转换就转换到numdata[1];再碰到逗号就记到numdata[2];以此类推,直到字符串结束
  188.       if(comdata[i] == ',')
  189.       {
  190.         j++;
  191.       }
  192.       else
  193.       {
  194.         //如果没有逗号的话,就将读到的数字*10加上以前读入的数字,
  195.         //并且(comdata[i] - '0')就是将字符'0'的ASCII码转换成数字0(下面不再叙述此问题,直接视作数字0)。
  196.         //比如输入数字是12345,有5次没有碰到逗号的机会,就会执行5次此语句。
  197.         //因为左边的数字先获取到,并且numdata[0]等于0,
  198.         //所以第一次循环是numdata[0] = 0*10+1 = 1
  199.         //第二次numdata[0]等于1,循环是numdata[0] = 1*10+2 = 12
  200.         //第三次是numdata[0]等于12,循环是numdata[0] = 12*10+3 = 123
  201.         //第四次是numdata[0]等于123,循环是numdata[0] = 123*10+4 = 1234
  202.         //如此类推,字符串将被变成数字0。
  203.         numdata[j] = numdata[j] * 10 + (comdata[i] - '0');
  204.       }
  205.     }
  206.     //comdata的字符串已经全部转换到numdata了,清空comdata以便下一次使用,
  207.     //如果不请空的话,本次结果极有可能干扰下一次。
  208.     comdata = String("");

  209.     period = numdata[0];
  210.     pulseWidthScaled = numdata[1];
  211.     Serial.println("P----------------");
  212.     if(digitalRead(pinKey) == HIGH){
  213.       Serial.println("IN2 & IN3 is actived! ");
  214.     }
  215.     else{
  216.       Serial.println("IN1 & IN4 is actived! ");
  217.     }
  218.     Serial.print("period: ");
  219.     Serial.println(period);
  220.     Serial.print("pulseWidthScaled: ");
  221.     Serial.println(pulseWidthScaled);
  222.     //循环输出numdata的内容,并且写到PWM引脚
  223.     for(int i = 0; i < 2; i++)
  224.     {
  225.       numdata[i] = 0;
  226.     }
  227.     //输出之后必须将读到数据的mark置0,不置0下次循环就不能使用了。
  228.     mark = 0;
  229.   }
  230. }

复制代码




Ref:
http://www.instructables.com/id/ ... or-Shield/?ALLSTEPS
Arduino学习笔记A6(补充) - 在串口读取多个字符串,并且转换为数字数组
http://www.geek-workshop.com/thread-260-1-1.html

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2015-6-19 13:27:18 | 显示全部楼层
不是有US级的么  
回复 支持 反对

使用道具 举报

发表于 2015-6-19 22:51:35 | 显示全部楼层
@幻生幻灭,为什么在中断程序里面没有重置TCNT1的值?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-23 09:13:16 | 显示全部楼层
wdjkzym 发表于 2015-6-19 13:27
不是有US级的么

毫秒级的不够么,如果我要产生 500 HZ 的方波,就得 2MS 一个周期,还怎么去控制电机的具体转速。。。。
回复 支持 反对

使用道具 举报

发表于 2015-6-23 18:46:26 | 显示全部楼层
songjiahaonanna 发表于 2015-6-23 09:13
毫秒级的不够么,如果我要产生 500 HZ 的方波,就得 2MS 一个周期,还怎么去控制电机的具体转速。。。。

              US、微秒
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-26 15:07:00 | 显示全部楼层
suoma 发表于 2015-6-23 18:46
US、微秒

定时器 1 有毫秒级别的,,,,找到了。。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-16 17:47 , Processed in 0.050116 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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