北京儿童插座价格联盟

Arduino基础实验教程

只看楼主 收藏 回复
  • - -
楼主

下面的实验是让学生初步掌握如何使用单片机,并配合基本电路元件实现一些有趣的功能。


单片机控制模块选用的是Arduino UNO R3,其集成开发环境Arduino IDE将很多复杂的底层操作都封装成函数,供初学者调用,大大降低了学习门槛,简化了编程工作量,非常适合零基础入门学习。


Arduino UNO R3开发板


注意,在Arduino环境下开发时,一定要善用串口监视器,这是一个好东西。


相关资源链接:

火花空间  http://www.oursparkspace.cn/

Arduino官网  https://www.arduino.cc/

开源软件托管平台  https://github.com/


另外,大家必须习惯于自己解决问题,习惯于利用搜索引擎去寻找问题的答案。


      很多事情就像是旅行一样,当你决定要出发的时候,最困难的部分其实就已经完成了。



基础实验



1. 自动控制路灯

要求:白天光照较强时,路灯关闭;晚上光照较弱,路灯开启。

设计思路:通过光敏元件感知光强,并通过mCookie控制路灯。


自动控制路灯原理图和接线图


注:按照左边的原理图来连接电路!不要按实物图。

       路灯用发光二极管代替,发光二极管必须串联限流电阻


参考代码:

int threshold =400; //光强值,根据实际情况调整

void setup ( )

{

    Serial.begin(115200);

    pinMode(10, OUTPUT);  //设置输出端口

}

void loop( )

{

    int n = analogRead(A3);   //读取模拟口A3

    Serial.println(n);

    if (n>threshold )         //晚上光线暗,n值变大

        digitalWrite(10, HIGH);    //点亮路灯

    else

        digitalWrite(10, LOW);     //关闭路灯

    delay(200);

}


注意:程序中的端口需根据实际电路连接修改,一定要跟电路连接的端口对应上。


思考题:

(1) 如何改成光强警示电路,光照较强时发光二极管点亮?

(2) 如何让发光二极管变成呼吸灯?   (提示:采用PWM方式控制LED)

(3) 如何设计自动调光台灯?    (提示:引入光敏电阻)

(4) 如何设计炫彩台灯?即控制彩色发光二极管,根据不同光强显示不同颜色的光。




2.数字温度计

要求:利用温度传感器检测环境温度,并通过IDE的串口监视器观察环境温度变化,环境温度越高发光二极管越亮,以适当方式呈现给用户。



数字温度计原理图和接线图


注:(1) 温度传感器采用LM35D,外形类似三极管,输出为模拟电压值,采集时每升高10mv电压代表温度上升1℃,两者成线性关系。

       (2) 该电路用的是内部基准源进行ADC采样,如果要实现精准测温,模数转换的基准电压必须稳定,mCookie的REF引脚应该外接精准电压源。

       (3) 实物图上未接发光二极管和蜂鸣器。



参考代码:

unsigned int tempMin = 29;      //亮灯温度

unsigned int tempMax = 33;     //报警温度

void setup( ) {

  Serial.begin(115200);             //串口初始化

  analogReference(INTERNAL);  //调用板载1.1V基准源

  pinMode(11, OUTPUT);

  digitalWrite(11, LOW);

}

void loop( ) {

   double analogVotage = 1.1*(double)analogRead(A3)/1023;

   double temp = 100*analogVotage; //计算温度

    unsigned int dutyCycle;                  //占空比

    if (temp <= tempMin) {        //小于亮灯门限值

        dutyCycle = 0; digitalWrite(11, LOW);

      }

    else if (temp < tempMax) {   //小于报警门限

         dutyCycle = (temp-tempMin)*255/(tempMax-tempMin);

         digitalWrite(11, LOW);

       }

    else{           //发光二极管亮度最大值,并启动声音报警

          dutyCycle = 255; digitalWrite(11, HIGH);

        }

  analogWrite(10, dutyCycle); //控制发光二极管发光

  Serial.print("Temp: ");  Serial.print(temp);

  Serial.print(" Degrees    Duty cycle: ");

  Serial.println(dutyCycle);

  delay(100); // 控制刷新速度

}


思考题:

(1) 如果通过彩色发光二极管显示环境温度变化?

(2) 如何利用七段数码管显示环境温度?

(3) 如何利用OLED屏显示环境温度?




3.智能温控风扇

要求:根据环境温度自动调节风扇转速。


智能温控风扇原理图和接线图



注:马达一般需要电流较大,单片机IO口驱动能力有限,所以要经过三极管进行电流放大,由于采用PWM方式,三极管工作在开关状态。


参考代码:

double analogVotage;  //模拟电压值

double temp;          //温度

unsigned int dutyCycle;  //占空比

unsigned int tempMin = 25;  //零速温度,设为串口观察到的环境温度

unsigned int tempMax = 35;  //满速温度,设为串口观察到的手握元件温度

void setup() {

  Serial.begin(115200);      //设置串口波特率

  analogReference(INTERNAL);  //调用板载1.1V基准源

}

void loop() {

  analogVotage = 1.1*(float)analogRead(A3)/1024;   //把ADC读取值换算成电压

  temp = 100*analogVotage;      //电压换算成温度

  if (temp < tempMin){

      dutyCycle = 0;

      }

  else if (temp < tempMax){

      dutyCycle = (temp-tempMin)*255/(tempMax-tempMin);

      }

  else {

      dutyCycle = 255;

      }

  analogWrite(10,dutyCycle);  //产生PWM

  Serial.print("Temp: "); Serial.print(temp);

  Serial.print(" Degrees    Duty cycle: ");

  Serial.println(dutyCycle);

  delay(100);    //等待0.1秒,控制刷新速度

}


思考题:

(1) 为什么没有用单片机IO口直接驱动马达?

(2) 如何让风扇感应到有人时才启动,并自动根据环境温度调节转速?

(3) 增加OLED屏,实时显示环境温度和风扇转速。


补充:热释电红外传感器前面装有菲涅尔透镜,可以很灵敏地检测到人体活动,这种传感器淘宝有很多,大家可根据需要购买。





4.同向比例运算电路

要求:利用集成运放,实现输入信号的线性放大。


同向比例运算原理图和接线图


注:输入可以采用电阻或电位器分压,淘宝上碳膜电位器很便宜,一元钱能买几个。如果输入信号过大,输出进入饱和。输入和输出的电压值用mCookie采集,通过IDE的串口观察器查看。


参考代码:

void  setup( ) {

  Serial.begin(115200);

}


void loop( ) {

 float vi=analogRead(A2)/1023.0*5;

 float vo=analogRead(A3)/1023.0*5;


 Serial.print("Input voltage is  "); 

 Serial.print(vi); Serial.println("V");


 Serial.print("Output voltage is "); 

 Serial.print(vo); Serial.println("V");

 delay(1000);

}


//在此程序中,用Arduino开发板的A2口采集输入模拟电压值,用A3口采集输出模拟电压值。



思考题:

(1) 如何更改放大倍数?放大倍数是否可以很大?

(2) 理论上,如何实现反向比例放大?




5.触摸电子琴

要求:通过手指触摸不同按键,弹奏不同的乐曲。

设计思路:利用Arduino的readCapacitivePin()函数,读取端口电容值;利用tone(pin, frequency)函数,产生不同的音调。



先做一个指尖开关实验

指尖开关也称为触摸开关。 本实验是利用人体电阻做开关,控制晶体三极管的导通,并以此控制发光二极管。


指尖开关原理图


用万用表测量,人体两只手的手指之间的电阻约在200千欧到2兆欧左右,与皮肤干燥程度有关。若手指未触摸开关,三极管的基极悬空,发射结be截止,三极管截止,A3点的电压由图中10k电阻拉低至0V。


用两手手指触摸开关时,等于将5V电压通过约1M欧的电阻加到三极管的基极,使三极管的发射结be因正偏而导通,三极管开启,虽然此时基极电流很小,但由于三极管的电流放大作用,流出发射极e的电流相对较大,在10k的发射极电阻上产生电压差,A3点为高电平。当Arduino UNO检测到A3点的电平为高时,将D13脚置为高电平,发光二极管被点亮。

参考代码

void setup()

{

  Serial.begin(115200);

  pinMode(10,OUTPUT);  

}

void loop()

{

  int n=analogRead(A3);   //读取模拟口数据        

  if(n>50)     //有电压反应就运行以下程序

    digitalWrite(10,HIGH); //点亮led

  else

    digitalWrite(10,LOW); //熄灭led

  Serial.println(n);//串口监视

  delay(100);//延时,控制刷新速率。

}



如何测量电容值

Arduino除了接收数字端口的数字信号,唯一能检测的模拟物理量就是电压。任何模拟传感器的检测值几乎都要通过相关电路转化成电压值,再输入Arduino的模拟端口进行模数转换。电容值就需要更复杂的电路转化为电压值,才能被Arduino检测。这里介绍一个除了一段导线和一个端口,不需要任何元器件的电容检测方法。 

这个方法的思路是,首先把一个数字端口设成低电位,并打开Arduino的内部上拉电阻,开始计算这个端口到达高电位所需要的时间。而这个时间与此端口的对地电容值有关,电容越大,时间越长。在硬件上只需要在一个端口上连一根导线即可。用手指触摸这段导线的裸露端,就会导致电容变化,Arduino可以通过上述方法检测这个变化。如果要增加灵敏度,可以在导线上连 一片锡箔。


注意:为防止静电造成Arduino核心模块的损坏,建议先触摸暖气等释放人体静电,或者在导线上盖一层绝缘板。


触摸开关

我们先通过触摸开关测试一下利用电容值检测端口是否被触摸,如果检测到手指碰触端口引线,则点亮LED灯。 实验的时候,触摸按键由D8口引出,用D11引脚控制LED灯。


参考代码

int ledPin = 11; //用D11引脚控制LED灯

    int capval;

    void setup()

    {

    pinMode(ledPin, OUTPUT);

    Serial.begin(115200);

    Serial.println("Touch senser");

    }

     

    void loop ()

    {

    digitalWrite(ledPin,LOW);

    capval = readCapacitivePin(8); //通过D8口读取电容值

    Serial.println(capval, DEC);

    if (capval > 2) {

    // turn LED on:

    digitalWrite(ledPin, HIGH);

    delay(10);

    }

    }

     

    uint8_t readCapacitivePin(int pinToMeasure) {

    // Variables used to translate from Arduino to AVR pin naming

    volatile uint8_t* port;

    volatile uint8_t* ddr;

    volatile uint8_t* pin;

    // Here we translate the input pin number from

    // Arduino pin number to the AVR PORT, PIN, DDR,

    // and which bit of those registers we care about.

    byte bitmask;

    port = portOutputRegister(digitalPinToPort(pinToMeasure));

    ddr = portModeRegister(digitalPinToPort(pinToMeasure));

    bitmask = digitalPinToBitMask(pinToMeasure);

    pin = portInputRegister(digitalPinToPort(pinToMeasure));

    // Discharge the pin first by setting it low and output

    *port &= ~(bitmask);

    *ddr |= bitmask;

    delay(1);

    // Make the pin an input with the internal pull-up on

    *ddr &= ~(bitmask);

    *port |= bitmask;

     

    // Now see how long the pin to get pulled up. This manual unrolling of the loop

    // decreases the number of hardware cycles between each read of the pin,

    // thus increasing sensitivity.

    uint8_t cycles = 17;

    if (*pin & bitmask) { cycles = 0;}

    else if (*pin & bitmask) { cycles = 1;}

    else if (*pin & bitmask) { cycles = 2;}

    else if (*pin & bitmask) { cycles = 3;}

    else if (*pin & bitmask) { cycles = 4;}

    else if (*pin & bitmask) { cycles = 5;}

    else if (*pin & bitmask) { cycles = 6;}

    else if (*pin & bitmask) { cycles = 7;}

    else if (*pin & bitmask) { cycles = 8;}

    else if (*pin & bitmask) { cycles = 9;}

    else if (*pin & bitmask) { cycles = 10;}

    else if (*pin & bitmask) { cycles = 11;}

    else if (*pin & bitmask) { cycles = 12;}

    else if (*pin & bitmask) { cycles = 13;}

    else if (*pin & bitmask) { cycles = 14;}

    else if (*pin & bitmask) { cycles = 15;}

    else if (*pin & bitmask) { cycles = 16;}

     

    // Discharge the pin again by setting it low and output

    // It's important to leave the pins low if you want to

    // be able to touch more than 1 sensor at a time - if

    // the sensor is left pulled high, when you touch

    // two sensors, your body will transfer the charge between

    // sensors.

    *port &= ~(bitmask);

    *ddr |= bitmask;

     

    return cycles;

    }


触摸电子琴

将Arduino UNO的A3口接无源蜂鸣器的正极,蜂鸣器的负极接地;然后将D2-D9口引出来作为触摸按键,烧入下面的程序,即可实现触摸电子琴的功能。


参考代码:


int ledPin = A3;//此处接无源蜂鸣器正极

int capval1,capval2,capval3,capval4,capval5,capval6,capval7,capval8;


void setup()

{

  pinMode(ledPin, OUTPUT);

  Serial.begin(9600);

  Serial.println("Touch senser");

}


void loop ()

{

  digitalWrite(ledPin,LOW);

  capval1 = readCapacitivePin(2); //D2管脚

  capval2 = readCapacitivePin(3);

  capval3 = readCapacitivePin(4);

  capval4 = readCapacitivePin(5);

  capval5 = readCapacitivePin(6);

  capval6 = readCapacitivePin(7);

  capval7 = readCapacitivePin(8);

  capval8 = readCapacitivePin(9); //D9管脚


  if (capval1 > 2) tone(ledPin, 262, 10);

  if (capval2 > 2) tone(ledPin, 294, 10);

  if (capval3 > 2) tone(ledPin, 330, 10);

  if (capval4 > 2) tone(ledPin, 350, 10);

  if (capval5 > 2) tone(ledPin, 393, 10);

  if (capval6 > 2) tone(ledPin, 441, 10);

  if (capval7 > 2) tone(ledPin, 495, 10);

  if (capval8 > 2) tone(ledPin, 525, 10);

}


uint8_t readCapacitivePin(int pinToMeasure) {

  // Variables used to translate from Arduino to AVR pin naming

  volatile uint8_t* port;

  volatile uint8_t* ddr;

  volatile uint8_t* pin;

  // Here we translate the input pin number from

  // Arduino pin number to the AVR PORT, PIN, DDR,

  // and which bit of those registers we care about.

  byte bitmask;

  port = portOutputRegister(digitalPinToPort(pinToMeasure));

  ddr = portModeRegister(digitalPinToPort(pinToMeasure));

  bitmask = digitalPinToBitMask(pinToMeasure);

  pin = portInputRegister(digitalPinToPort(pinToMeasure));

  // Discharge the pin first by setting it low and output

  *port &= ~(bitmask);

  *ddr |= bitmask;

  delay(1);

  // Make the pin an input with the internal pull-up on

  *ddr &= ~(bitmask);

  *port |= bitmask;


  // Now see how long the pin to get pulled up. This manual unrolling of the loop

  // decreases the number of hardware cycles between each read of the pin,

  // thus increasing sensitivity.

  uint8_t cycles = 17;

  if (*pin & bitmask) 

    cycles = 0;

  else if (*pin & bitmask) 

    cycles = 1;

  else if (*pin & bitmask) 

    cycles = 2;

  else if (*pin & bitmask) 

    cycles = 3;

  else if (*pin & bitmask) 

    cycles = 4;

  else if (*pin & bitmask) 

    cycles = 5;

  else if (*pin & bitmask) 

    cycles = 6;

  else if (*pin & bitmask) 

    cycles = 7;

  else if (*pin & bitmask) 

    cycles = 8;

  else if (*pin & bitmask) 

    cycles = 9;

  else if (*pin & bitmask) 

    cycles = 10;

  else if (*pin & bitmask) 

    cycles = 11;

  else if (*pin & bitmask) 

    cycles = 12;

  else if (*pin & bitmask) 

    cycles = 13;

  else if (*pin & bitmask) 

    cycles = 14;

  else if (*pin & bitmask) 

    cycles = 15;

  else if (*pin & bitmask) 

    cycles = 16;


  // Discharge the pin again by setting it low and output

  // It's important to leave the pins low if you want to 

  // be able to touch more than 1 sensor at a time - if

  // the sensor is left pulled high, when you touch

  // two sensors, your body will transfer the charge between

  // sensors.

  *port &= ~(bitmask);

  *ddr |= bitmask;


  return cycles;

}





呼吸灯

利用脉冲宽度调制PWM可以控制发光二极管逐渐亮暗,实现呼吸等效果。电路连接很简单,将程序下载到板子上后,可以看到LED灯由暗慢慢变亮,再由亮渐暗到灭,依次循环,像是在呼吸一样。



参考代码

int brightness = 0;       //表示LED的亮度

int fadeAmount = 5;    //LED亮度变化增量

void setup()

{

   pinMode(11, OUTPUT);     // 设置11号口为输出端口

} 

void loop()

{

   analogWrite(11, brightness);       //把brightness值写入端口

   brightness = brightness + fadeAmount;  //使亮度在下一次循环发生改变 

   if (brightness <= 0 || brightness >= 255)

       fadeAmount = -fadeAmount ;       //在亮度最高或最低时进行翻转

   delay(30);      //延时30毫秒


光控电子琴

利用光敏电阻检测光照强度,并以此控制无源蜂鸣器发生不同的音调,便成了光控电子琴。


电路原理图



实物图

为方便起见,用Arduino UNO R3代替mCookie。


参考程序

//定义音阶常量  

#define Do 262  

#define Re 294  

#define Mi 330  

#define Fa 349  

#define Sol 392  

#define La 440  

#define Si 494  

int val=0; 

int buzzerPin=7;   //定义蜂鸣器针脚  

 

void setup(){  

  Serial.begin(115200);

  pinMode(buzzerPin,OUTPUT);  

}  


void loop()

{

   int n = analogRead(A0);   //读取模拟口A0,获取光强

   Serial.println(n);        // 用于IDE串口观察窗

   val=0;

   if(n<=200) 

     val=Do;

   else if(n<=220)

     val=Re;

   else if(n<=240)

     val=Mi;

   else if (n<=300) 

     val=Fa;

   else if (n <=350) 

     val=Sol;

   else if (n<=400) 

     val=La;

   else if (n<=500) 

     val=Si;

   if (val)

   {

     tone(buzzerPin,val,1000);

     delay(1000); 

    }

    else

     delay(100); //防止写串口速度过快

}


进阶实验



焦耳小偷电路


单管共射放大电路


LM386音频放大电路


炫彩闪光棒


激光PM2.5检测仪


口袋实验仪器AD2


Arduino UNO板的使用



举报 | 1楼 回复

友情链接