|
如何使用Basra主控板
作者:机器谱
概述 配置环境及编程 使用串口 使用EEPROM 定时器扩展库 解舵机电机冲突 解boolean冲突 |
1.简介
Basra是一款基于Arduino开源方案设计的一款开发板,通过各种各样的传感器来感知环境,通过控制灯光、马达和其他的装置来反馈、影响环境。板子上的微控制器可以在Arduino、eclipse、Visual Studio等IDE中通过c/c++语言来编写程序,编译成二进制文件,烧录进微控制器。Basra的处理器核心是ATmega328,同时具有14路数字输入/输出口(其中6路可作为PWM输出),6路模拟输入,一个16MHz晶体振荡器,一个USB口,一个电源插座,一个ICSP header和一个复位按钮。
主CPU采用AVR ATMEGA328型控制芯片,支持C语言编程方式;该系统的硬件电路包括:电源电路、串口通信电路、MCU基本电路、烧写接口、显示模块、AD/DA转换模块、输入模块、IIC存储模块等其他电路模块电路。控制板尺寸不超过60*60mm,便于安装。CPU硬件软件全部开放,除能完成对小车控制外,还能使用本实验板完成单片机所有基础实验。供电范围宽泛,支持5v~9v的电压,干电池或锂电池都适用。编程器集成在控制板上,通过USB大小口的方式与电脑连接。下载程序。开放全部底层源代码。控制板含3A6V的稳压芯片,可为舵机提供6v额定电压。板载8*8led模块采用MAX7219驱动芯片。板载2片直流电机驱动芯片L9170,可驱动两个直流电机。板载USB驱动芯片及自动复位电路,烧录程序时无需手动复位。2个2*5的杜邦座扩展坞,方便无线模块、OLED、蓝牙等扩展模块直插连接,无需额外接线。
· 工作电压 5V
· 输入电压(推荐) 7-12V
· 输入电压(范围) 6-20V
· 数字IO脚 14 (其中6路作为PWM输出)
· 模拟输入脚 6
· IO脚直流电流 40 mA
· 3.3V脚直流电流 50 mA
· Flash Memory 32 KB (ATmega328,其中0.5 KB 用于 bootloader)
· SRAM 2 KB (ATmega328)
· EEPROM 1 KB (ATmega328)
· 工作时钟 16 MHz
Basra可以通过3种方式供电,而且能自动选择供电方式
· 外部直流电源通过电源插座供电。
· 电池连接电源连接器的GND和VIN引脚。
· USB接口直接供电。
电源引脚说明
VIN --- 当外部直流电源接入电源插座时,可以通过VIN向外部供电;也可以通过此引
脚向UNO直接供电;VIN有电时将忽略从 USB或者其他引脚接入的电源。
5V --- 通过稳压器或USB的5V电压,为UNO上的5V芯片供电。
3.3V --- 通过稳压器产生的3.3V电压,最大驱动电流50mA。
GND --- 地脚。
ATmega328包括了片上32KB Flash,其中0.5KB用于Bootloader。同时还有2KB SRAM和1KB EEPROM。
14路数字输入输出口:工作电压为 5V,每一路能输出和接入最大电流为40mA。每一路配置了20-50K欧姆内部上拉电阻(默认不连接)。除此之外,有些引脚有特定的功能:
· 串口信号RX(0号)、TX(1号): 与内部 ATmega8U2 USB-to-TTL 芯片相连,提供TTL电压水平的串口接收信号。
· 外部中断(2号和3号):触发中断引脚,可设成上升沿、下降沿或同时触发。
· 脉冲宽度调制PWM(3、5、6、9、10 、11):提供6路8位PWM输出。
· SPI(10(SS),11(MOSI),12(MISO),13(SCK)):SPI通信接口。
· LED(13号):Arduino专门用于测试LED的保留接口,输出为高时点亮LED,反之输出为低时LED熄灭。
6路模拟输入A0到A5:每一路具有10位的分辨率(即输入有1024个不同值),默认输入信号范围为0到5V,可以通过AREF调整输入上限。除此之外,有些引脚有特定功能
· TWI接口(SDA A4和SCL A5):支持通信接口(兼容I2C总线)。
AREF:模拟输入信号的参考电压。
Reset:信号为低时复位单片机芯片。
· 串口:ATmega328内置的UART可以通过数字口0(RX)和1(TX)与外部实现串口通信;
ATmega16U2可以访问数字口实现USB上的虚拟串口。
· TWI(兼容I2C)接口
· SPI 接口
Basra上的ATmega328已经预置了bootloader程序,因此可以通过Arduino软件直接下载程序到主控板中。可以直接通过主控板上ICSP header直接下载程序到ATmega328。
· USB口附近有一个可重置的保险丝,对电路起到保护作用。当电流超过500mA时会断开USB连接。
· 主控板提供了自动复位设计,可以通过主机复位。这样通过Arduino软件下载程序到主控板中时,软件可以自动复位,不需要在复位按钮。
序号 | 内容 |
1 | Basra相关原理图引脚图电路文件等 |
本篇资源(概述及其它文章),参考了以下资料:
1.【图书】程晨,《Arduino开发实战指南》,机械工业出版社,2012.2
2.【图书】Simon Monk,《基于Arduino的趣味电子制作》,科学出版社,2011
3.【图书】Dale Wheat著,翁恺 译,《Arduino技术内幕》,人民邮电出版社,2013.4
7.【MCU Datasheet】..\Basra控制板\参考资料\ATmega328P.pdf
8.【USB-UART Datasheet】..\Basra控制板\参考资料\FT232RL.pdf
10.【串口的一些高级用法 】
14.资料下载
11. 芯片与接口引脚
12. 原理图
【整体打包】-【U006】如何使用Basra控制板-概述-资料下载.zip | 37.67MB | 下载112次 | 下载 |
1. 所需部件
Basra控制板及配件。配件如下表所示:
Basra控制板 | miniUSB数据线 | Windows系统的电脑 |
2. 在windows系统上配置编程环境
(1)下载并拷贝Arduino编程软件目录至本机位置,下载地址:https://www.arduino.cc/
(2)将Basra控制板通过miniUSB数据线与PC连接,初次连接时会弹出驱动安装提示。选择..\tools\arduino-1.x.x\drivers\FTDI USB Drivers目录安装驱动。
(3)打开设备管理器,在端口列表中,出现USB Serial Port (COMx),表示驱动安装成功。请记录下这个COM端口号x,下图中端口号为COM3。
(4)在本机上运行arduino-1.x.x目录下的arduino.exe,显示如下界面(以1.8.19中文版为例):
(5)在“工具”菜单下,依次选择:
开发板→Arduino AVR Boards→Arduino/Genuino Uno;
以及:端口→COM3(COM3为步骤3里记录下的端口号)。
此时在界面右下角显示“Arduino Uno/Genuino 在 COM3”。
(6)点击上传按钮,一个空白的程序将自动烧录进Basra控制板。具体过程如下图所示:
开始编译代码
开始向Basra控制板烧录程序,烧录过程中控制板上的TX/RX指示灯闪动
烧录成功
3. 最简编程项目:Blink
打开“文件→示例→01.Basic→Blink”,弹出Blink例程窗口,将程序上传到Basra控制板中,观察D13 Led灯的变化。
本实验例程源代码如下:
/* Blink Turns an LED on for one second, then off for one second, repeatedly. Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to the correct LED pin independent of which board is used. If you want to know what pin the on-board LED is connected to on your Arduino model, check the Technical Specs of your board at: https://www.arduino.cc/en/Main/Products modified 8 May 2014 by Scott Fitzgerald modified 2 Sep 2016 by Arturo Guadalupi modified 8 Sep 2016 by Colby Newman This example code is in the public domain. https://www.arduino.cc/en/Tutorial/BuiltInExamples/Blink */ // the setup function runs once when you press reset or power the board void setup() { // initialize digital pin LED_BUILTIN as an output. pinMode(LED_BUILTIN, OUTPUT); } // the loop function runs over and over again forever void loop() { digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW delay(1000); // wait for a second } |
可以尝试改变delay()函数的参数,观察Led的闪动有什么变化。
1.显示输入信息
打开“文件→示例→04.Communication-SerialEvent”,将例程上传到Basra控制板中。
在“工具”中打开“串口监视器”,下侧依次选择“换行符”以及“9600 波特率”,如下图所示。
在上侧对话框中输入任何内容后回车,文本就会被发送到Basra控制板;控制板收到文本后,会将内容发回给上位机,并显示在中间的文本框中。
本实验例程源代码如下:
/* Serial Event example When new serial data arrives, this sketch adds it to a String. When a newline is received, the loop prints the string and clears it. A good test for this is to try it with a GPS receiver that sends out NMEA 0183 sentences. NOTE: The serialEvent() feature is not available on the Leonardo, Micro, or other ATmega32U4 based boards. created 9 May 2011 by Tom Igoe This example code is in the public domain. https://www.arduino.cc/en/Tutorial/BuiltInExamples/SerialEvent */ String inputString = ""; // a String to hold incoming data bool stringComplete = false; // whether the string is complete void setup() { // initialize serial: Serial.begin(9600); // reserve 200 bytes for the inputString: inputString.reserve(200); } void loop() { // print the string when a newline arrives: if (stringComplete) { Serial.println(inputString); // clear the string: inputString = ""; stringComplete = false; } } /* SerialEvent occurs whenever a new data comes in the hardware serial RX. This routine is run between each time loop() runs, so using delay inside loop can delay response. Multiple bytes of data may be available. */ void serialEvent() { while (Serial.available()) { // get the new byte: char inChar = (char)Serial.read(); // add it to the inputString: inputString += inChar; // if the incoming character is a newline, set a flag so the main loop can // do something about it: if (inChar == '\n') { stringComplete = true; } } } |
2.计算器小程序
在Basra控制板上编写一个计算器的小程序,使得可以在上位机的串口监视器中输入运算式后,Basra将计算结果返回给上位机。
String inputString = ""; // a string to hold incoming data boolean stringComplete = false; // whether the string is complete void setup() { // initialize serial: Serial.begin(9600); // reserve 200 bytes for the inputString: inputString.reserve(200); } void loop() { if(stringComplete) //判断是否有数据输入 { stringComplete = false; Serial.println((String)(calculate())); //打印结果 } } /****************************************** 函数名称:calculate 函数功能:对输入数据进行四则运算 函数参数:无 返 回 值:运算结果 ******************************************/ int calculate() { char case_deal; int a, b, result, location; String tmp; inputString.trim(); //去掉回车 Serial.print(inputString + '='); //运算符号判断 if((location = (inputString.indexOf('+'))) > 0) { case_deal = 1; } else if((location = (inputString.indexOf('-'))) > 0) { case_deal = 2; } else if((location = (inputString.indexOf('*'))) > 0) { case_deal = 3; } else if((location = (inputString.indexOf('/'))) > 0) { case_deal = 4; } else { Serial.println("error"); //错误处理 return -1; } tmp = inputString.substring(0, location); //解析第一个数字 a = tmp.toInt(); //将字符串转换成数字 tmp = inputString.substring(location+1); //解析第二个数字 b = tmp.toInt(); //将字符串转换成数字 switch (case_deal) //运算处理 { case 1: result = a + b; break; case 2: result = a - b; break; case 3: result = a * b; break; case 4: result = a / b; break; default: result = -1; } inputString = ""; //输入清空,不然下次读入出错 return result; } void serialEvent() { while (Serial.available()) { // get the new byte: char inChar = (char)Serial.read(); // add it to the inputString: inputString += inChar; // if the incoming character is a newline, set a flag // so the main loop can do something about it: if (inChar == '\n') { stringComplete = true; } } } |
序号 | 内容 |
1 | 计算器小程序源代码 |
【整体打包】-【U006】如何使用Basra控制板-使用串口(Serial)-计算器例程.zip | 1.85KB | 下载2次 | 下载 |
1. 存储字节型数据
(1)打开“文件→示例→EEPROM→eeprom_clear”,将例程上传到Basra控制板中,清空eeprom里的数据。
(2)打开“文件→示例→EEPROM→eeprom_read”,将例程上传到Basra控制板中,然后打开“串口监视器”,观察EEPROM里的数据情况。左侧为EEPROM的存储地址序号,右侧为相应的存储空间内的数值。由于在上一步中清空了EERPOM,所以所有的存储空间内的数值都为0。如下图所示。
(3)、打开“文件→示例→EEPROM→eeprom_write”,将例程uploading到Basra控制板中。本例程每100ms读取一次A0端口的数值,并按地址顺序存储到EEPROM中。由于在这个实验中,A0端口没有连接任何外设,所以每次读取的A0端口的值会不确定。
(4)、再次回到第2步的内容,此时EEPROM里已经有了数据了,如下图所示:
本实验例程源代码如下:
/* * EEPROM Clear * * Sets all of the bytes of the EEPROM to 0. * Please see eeprom_iteration for a more in depth * look at how to traverse the EEPROM. * * This example code is in the public domain. */ #include <EEPROM.h> void setup() { // initialize the LED pin as an output. pinMode(13, OUTPUT);
/*** Iterate through each byte of the EEPROM storage. Larger AVR processors have larger EEPROM sizes, E.g: - Arduno Duemilanove: 512b EEPROM storage. - Arduino Uno: 1kb EEPROM storage. - Arduino Mega: 4kb EEPROM storage. Rather than hard-coding the length, you should use the pre-provided length function. This will make your code portable to all AVR processors. ***/ for (int i = 0 ; i < EEPROM.length() ; i++) { EEPROM.write(i, 0); } // turn the LED on when we're done digitalWrite(13, HIGH); } void loop() { /** Empty loop. **/ } /* * EEPROM Read * * Reads the value of each byte of the EEPROM and prints it * to the computer. * This example code is in the public domain. */ #include <EEPROM.h> // start reading from the first byte (address 0) of the EEPROM int address = 0; byte value; void setup() { // initialize serial and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } } void loop() { // read a byte from the current address of the EEPROM value = EEPROM.read(address); Serial.print(address); Serial.print("\t"); Serial.print(value, DEC); Serial.println(); /*** Advance to the next address, when at the end restart at the beginning. Larger AVR processors have larger EEPROM sizes, E.g: - Arduno Duemilanove: 512b EEPROM storage. - Arduino Uno: 1kb EEPROM storage. - Arduino Mega: 4kb EEPROM storage. Rather than hard-coding the length, you should use the pre-provided length function. This will make your code portable to all AVR processors. ***/ address = address + 1; if (address == EEPROM.length()) { address = 0; } /*** As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an EEPROM address is also doable by a bitwise and of the length - 1. ++address &= EEPROM.length() - 1; ***/ delay(500); } /* * EEPROM Write * * Stores values read from analog input 0 into the EEPROM. * These values will stay in the EEPROM when the board is * turned off and may be retrieved later by another sketch. */ #include <EEPROM.h> /** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ int addr = 0; void setup() { /** Empty setup. **/ } void loop() { /*** Need to divide by 4 because analog inputs range from 0 to 1023 and each byte of the EEPROM can only hold a value from 0 to 255. ***/ int val = analogRead(0) / 4; /*** Write the value to the appropriate byte of the EEPROM. these values will remain there when the board is turned off. ***/ EEPROM.write(addr, val); /*** Advance to the next address, when at the end restart at the beginning. Larger AVR processors have larger EEPROM sizes, E.g: - Arduno Duemilanove: 512b EEPROM storage. - Arduino Uno: 1kb EEPROM storage. - Arduino Mega: 4kb EEPROM storage. Rather than hard-coding the length, you should use the pre-provided length function. This will make your code portable to all AVR processors. ***/ addr = addr + 1; if (addr == EEPROM.length()) { addr = 0; } /*** As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an EEPROM address is also doable by a bitwise and of the length - 1. ++addr &= EEPROM.length() - 1; ***/ delay(100); } |
2. 存储其他类型数据
使用Arduino提供的EEPROM API,只能将字节型的数据的存入EEPROM。如果要存储字节以外的数据类型,又需要怎么做呢?
一个float类型的数据,需要占用4个字节的存储空间。因此我们可以把一个float拆分为4个字节,然后逐字节的写入EEPROM,来达到保存float数据的目的。
这里我们使用共用体,把float数据拆分为4个字节。
共用体:几个不同的变量共同占用一段内存的结构,在C语言中,被称作共用体类型结构,简称共用体。
首先定义一个名为data的共用体结构,共用体中有两个类型不同的成员变量:
union data{ float a; byte b[4]; }; |
#include <EEPROM.h> union data { float a; byte b[4]; }; data col; int addr = 0; int led = 13; void setup() { for(int i=0;i<4;i++) col.b[i]=EEPROM.read(i); Serial.begin(9600); } void loop() { //输出 Serial.println(col.a); delay(1000); } |
#include <EEPROM.h> union data { float a; byte b[4]; }; data col; int addr = 0; int led = 13; void setup() { col.a=987.65; for(int i=0;i<4;i++) EEPROM.write(i, col.b[i]); pinMode(led, OUTPUT); } void loop() { //LED闪烁,提示任务已完成 digitalWrite(led, HIGH); delay(1000); digitalWrite(led, LOW); delay(1000); } |
data col; |
再申明一个data类型的变量col:
现在你可以通过col.a访问这个共用体中的float类型成员a,通过col.b访问这个共用体中的byte类型成员b。col.a和col.b共同占用四个字节的地址。给col.a赋值后,通过col.b即可拆分float的目的。
这里我们提供一个将float类型存入EEPROM的例程。
读出储存在EEPROM中的float类型数据思路和写入时相同,完整代码如下:
显示效果如下:
3. 练习题
编写一个程序,使用串口监视器向Basra控制板发送一段内容,控制板将这段内容储存在EEPROM中。每次控制板重新启动后,Basra都能将这段内容输出给上位机显示。
4. 资料清单
序号 | 内容 |
1 | 写入浮点数例程源代码 |
2 | 读取浮点数例程源代码 |
3 | 练习题参考答案源代码 |
【整体打包】-【U006】如何使用Basra控制板通识-使用EEPROM-附件资料.zip | 3.91KB | 下载1次 | 下载 |
1.关于扩展库
在EEPROM实验中,我们使用了一个头文件<EEPROM.h>,这让我们很方便的就可以使用EEPROM的存储读写功能,而不用去艰涩的学习与EEPROM有关的硬件操作。
Arduino还有大量的扩展库,可以使相关的硬件应用变得更简单,如OLED、无线模块、温度传感器等等,这些模块在扩展库的帮助下,能让我们很快的上手来做应用,而不用花1个月的时间去钻研各种硬件的特性与芯片资料。当然,如果在嵌入式技术领域进行深入的学习,那么自己动手给各种硬件做扩展库则是非常必要的。
2. 定时器
Basra有3个定时器,分别是timer0、timer1、timer2。一般情况下,调用定时器要写类似下面的代码(这段代码的功能是将三个定时器同时开启):
int toggle0,toggle1,toggle2=0; void setup(){ cli();////关闭全局中断 //设置定时器0为10kHz(100us) TCCR0A = 0;//将整个TCCR0A寄存器设置为0 TCCR0B = 0;//将整个TCCR0B寄存器设置为0 TCNT0 = 0;//将计数器值初始化为0 //设置计数器为10kHZ,即100us OCR0A = 24;//比较匹配寄存器= [16,000,000Hz /(预分频器*所需中断频率)] - 1 //比较匹配寄存器=24,中断间隔=100us即中断频率10khz TCCR0A |= (1 << WGM01);//打开CTC模式 TCCR0B |= (1 << CS01) | (1 << CS00); //设置CS01位为1(8倍预分频) TIMSK0 |= (1 << OCIE0A);//启用定时器比较中断
//设置定时器1为1kHz TCCR1A = 0;//将整个TCCR1A寄存器设置为0 TCCR1B = 0;//将整个TCCR1B寄存器设置为0 TCNT1 = 0;//将计数器值初始化为0 //设置计数器为10kHZ,即1ms OCR1A = 199;// = (16*10^6)/(1000*8) - 1 (must be <65536) TCCR1B |= (1 << WGM12);//打开CTC模式 TCCR1B |= (1 << CS11);//设置CS11位为1(8倍预分频) TIMSK1 |= (1 << OCIE1A); //设置定时器2为8kHz TCCR2A = 0;// set entire TCCR2A register to 0 TCCR2B = 0;// same for TCCR2B TCNT2 = 0;//initialize counter value to 0 // set compare match register for 8khz increments OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256) // turn on CTC mode TCCR2A |= (1 << WGM21);//打开CTC模式 // Set CS21 bit for 8 prescaler TCCR2B |= (1 << CS21); // enable timer compare interrupt TIMSK2 |= (1 << OCIE2A); sei();//打开全局中断 } //中断0服务函数 ISR(TIMER0_COMPA_vect){ //产生频率为2kHz / 2 = 1kHz的脉冲波(全波切换为两个周期,然后切换为低) if(toggle0){ digitalWrite(8,HIGH); toggle0 = 0; } else{ digitalWrite(8,LOW); toggle0 = 1; } } ISR(TIMER1_COMPA_vect){// timer1中断1Hz切换引脚13(LED) //产生频率为1Hz / 2 = 0.5kHz的脉冲波(全波切换为两个周期,然后切换为低) if(toggle1){ digitalWrite(13,HIGH); toggle1 = 0; } else{ digitalWrite(13,LOW); toggle1 = 1; } }
ISR(TIMER2_COMPA_vect){// timer1中断8kHz切换引脚9 //产生频率为8kHz / 2 = 4kHz的脉冲波(全波切换为两个周期,然后切换为低) if(toggle2){ digitalWrite(9,HIGH); toggle2 = 0; } else{ digitalWrite(9,LOW); toggle2 = 1; } } void loop(){
} |
#include <MsTimer2.h> // Switch on LED on pin 13 each second void flash() { static boolean output = HIGH;
digitalWrite(13, output); output = !output; } void setup() { pinMode(13, OUTPUT); MsTimer2::set(500, flash); // 500ms period MsTimer2::start(); } void loop() { } |
这种代码的可读性比较差,用户读起来、用起来都比较吃力。
3. MsTimer2扩展库
下面我们尝试安装一个timer2定时器的扩展库MsTimer2,这个Mstimer2扩展库就是把类似上文的代码封装到一个或几个函数里,需要时调用这些函数进行控制就可以了。
Windows系统安装扩展库:
拷贝扩展库MsTimer2文件夹至本机arduino的..\arduino-1.x.x\libraries下即可。
Ubuntu系统安装扩展库:
拷贝扩展库MsTimer2文件夹至本机Ubuntu 的/home/ubuntu/Arduino/libraries下即可。
MsTimer2扩展库包含3个内容。MsTimer2.h是头文件,告诉用户这个库文件都声明了哪些功能,都包含了哪些子函数等;MsTimer2.cpp为函数说明文件,具现了.h文件中的每一个功能,就是用代码去实现.h文件中的每一个函数。examples文件夹中包含一个FlashLed.pde文件,是库函数的使用例程。
启动Arduino IDE,可以发现,在示例中多了一个MsTimer2的例程FlashLed。
打开“文件→示例→MsTimer2→FlashLed”,将例程上传到Basra控制板中。这个例程使用MsTimer2库函数实现了Blink的功能。
本实验例程FlashLed源代码如下:
4. 资料清单
序号 | 内容 |
1 | MsTimer2扩展库 |
【整体打包】-【U006】如何使用Basra控制板-5.定时器扩展库-下载附件.zip | 4.23KB | 下载11次 | 下载 |
解决舵机电机冲突
1. 问题描述
探索者Basra控制板是基于Arduino UNO版型设计,该版型设计时D9,D10端口直流电机口PWM波调速时用到的定时器与控制伺服电机用到的定时器是同一个Timer1,所以当直流电机口D9,D10端口和舵机同时工作时会出现定时器冲突。
2. 需要用到的电子硬件
主控板 | |
扩展板 | |
电池 | 7.4V锂电池 |
其它 | 伺服电机x1,直流电机x2 |
/*------------------------------------------------------------------------------------ 版权说明:Copyright 2023 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved. Distributed under MIT license.See file LICENSE for detail or copy at https://opensource.org/licenses/MIT by 机器谱 2023-05-25 https://www.robotway.com/ ------------------------------*/ #include<ServoTimer2.h> #define myservoPin 3 ServoTimer2 myservo;//注意与声明的头文件保持一致 int a; void setup() { // put your setup code here, to run once: myservo.attach(myservoPin); pinMode( 9 , OUTPUT ); pinMode( 10 , OUTPUT ); pinMode( 5, OUTPUT ); pinMode( 6, OUTPUT ); } void loop() { // put your main code here, to run repeatedly: a=map(60,0,180,750,2250); myservo.write(a); analogWrite( 9 , 200 ); analogWrite(5 , 200 ); delay(1000); a=map(120,20,160,750,2250);////这是一个映射函数 myservo.write(a); //注意a=map(60,20,160,750,2250),其中a=map(转动到的角度,可转动角度最小值,转动角度最大值,最小可转动的角度值对应的脉冲,最大可转动的角度值对应的脉冲) analogWrite( 9 ,100 ); analogWrite( 5 ,100 ); delay(1000); } |
/*------------------------------------------------------------------------------------ 版权说明:Copyright 2023 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved. Distributed under MIT license.See file LICENSE for detail or copy at https://opensource.org/licenses/MIT by 机器谱 2023-05-25 https://www.robotway.com/ ------------------------------*/ int servoPin = 3; //定义舵机接口数字接口7 也就是舵机的橙色信号线。 int speedd=200; void setup() { pinMode(servoPin, OUTPUT); //设定舵机接口为输出接口 pinMode( 5 , OUTPUT); pinMode( 6 , OUTPUT); //直流电机输出端 pinMode( 9 , OUTPUT); pinMode( 10 , OUTPUT); }
void loop() { servo(30); analogWrite( 5 , 0 ); analogWrite( 6 , speedd ) ; //左轮速度(正转) analogWrite( 9 , speedd ); analogWrite( 10 , 0); // delay(600); servo(60); delay(600); analogWrite( 5 , speedd ); analogWrite( 6 , 0 ) ; //左轮速度(正转) analogWrite( 9 , 0 ); analogWrite( 10 , speedd); servo(90); delay(600); }
void servo(int angle) { //定义一个脉冲函数 //发送50个脉冲 for(int i=0;i<50;i++){ int pulsewidth = (angle * 11) + 500; //将角度转化为500-2480的脉宽值 digitalWrite(servoPin, HIGH); //将舵机接口电平至高 delayMicroseconds(pulsewidth); //延时脉宽值的微秒数 digitalWrite(servoPin, LOW); //将舵机接口电平至低 delayMicroseconds(20000 - pulsewidth); } delay(100); } |
3. 问题解决
方法一:调用ServoTime2函数库
Arduino UNO上有3个定时器Timer0、Timer1、Timer2。D5/D6端口用的是Timer 0;D9/D10端口用的是Timer1;舵机函数库默认也用Timer1,我们可以考虑改用Timer2。
操作步骤:
① 安装ServoTimer2函数库,将 ServoTimer2文件夹 拷贝到Arduino IDE的libraries文件夹里;
② 将两个直流电机连接到Bigfish扩展板对应的D5、D6;D9、D10端口,伺服电机连接到D3端口。
③ 下载程序:下面提供一个参考程序(sketch_may25a.ino),此程序调用了ServoTimer2函数库,可成功解决探索者Basra控制器直流电机调速与舵机工作的冲突问题,适用于Arduino UNO。
编程环境:Arduino 1.8.19
方法二:自己写个新的舵机控制函数
从舵机控制的原理出发,舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,所以我们写一个脉冲函数来实现此功能。
操作步骤:
① 将两个直流电机连接到Bigfish扩展板对应的D5、D6;D9、D10端口,舵机连接到D3端口。
(2)编写程序:大家可尝试写一段新的Servo函数,这段函数不使用ServoTimer1,从而避免冲突。下面提供一个新编写的Servo函数参考程序(akldjhfl.ino):
4. 资料清单
序号 | 内容 |
1 | 程序源代码 |
【整体打包】-【U006】如何使用Basra主控板-解决舵机电机冲突-资料附件.zip | 18.44KB | 下载44次 | 下载 |
解boolean冲突
当大家使用ServoTimer2库的例程在arduino1.8版本上编译时,有可能会出现以下错误:
错误提示包含:
Typedef unit8 boolean;
typedef bool boolean;
exit status 1字样。
这是因为ServoTimer2库里定义了boolean这个类型,而1.8以上版本的Arduino框架里默认包含了boolean类型,我们所用的ServoTimer2库就和Arduino软件重复定义了。
解决办法:
在ServoTimer2库中找到ServoTimer2.h文件,把typedef uint8_ boolean这句代码注释掉即可【大家也可以从文末资料中下载已经处理好的ServoTimer2库】。
注意:1.8以下版本的Arduino软件框架不包含boolean类型,因此还需要保留此句代码。
资料清单
序号 | 内容 |
1 | ServoTimer2库 |
【整体打包】-【U006】如何使用Basra主控板-解boolean冲突-资料附件.rar | 4.96KB | 下载12次 | 下载 |