序言
玩起arduino其实一直没有好好的把arduino的基本操作过一遍,今天本小白就忙里偷闲干了这件事情,当然,首先还是要把之前的bug解决一下。
上一篇OLED的bug
尝试oled分屏显示的时候,本来是因为每屏的内容不同,所以进行了分几屏显示的操作。
后来做单屏滚动的时候,是想在一屏里解决的,但是总会出现显示提前结束的bug。
于是我想起来我改过一个变量的类型。
unsigned long draw_state = 0;
为了增长显示时间,我把类型改成了unsigned long
但是在函数调用的时候我没有改。。。
错误如下:
void u8g_print1(uint8_t a) {
case 0 : u8g_print1 (draw_state&(uint8_t)(pow(2,Con_interval)-1));
这两行代码里数据类型都用的是unsigned char…
于是把这两行修改之后,程序就正常运行了。【揭棺而起.jpg】
代码如下:
#include "U8glib.h"
U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE); // I2C / TWI
# define Con_interval 11
# define Con_pages 1
void u8g_prepare(void) {
u8g.setFont(u8g_font_6x10);
u8g.setFontRefHeightExtendedText();
u8g.setDefaultForegroundColor();
u8g.setFontPosTop();
}
void u8g_print1(unsigned long a) {
u8g.drawStr( 0, 0-a/8, "Schools apart,");
u8g.drawStr( 0, 11-a/8, "day after day,");
u8g.drawStr( 0 ,22-a/8, "And I slowly ");
u8g.drawStr( 0 ,33-a/8, "go insane.");
u8g.drawStr( 0 ,44-a/8, "But you left");
u8g.drawStr( 0, 55-a/8, "which was");
u8g.drawStr( 0, 66-a/8, "my deep pain.");
u8g.drawStr( 0, 77-a/8, "Since you've");
u8g.drawStr( 0, 88-a/8, "broken my heart,");
u8g.drawStr( 0, 99-a/8, "you need not");
u8g.drawStr( 0, 110-a/8, "be with me.");
u8g.drawStr( 0, 121-a/8, "Let's say goodbye");
u8g.drawStr( 0, 132-a/8, "and depart,");
u8g.drawStr( 0, 143-a/8, "And I'm what");
u8g.drawStr( 0, 154-a/8, "I used to be.");
u8g.drawStr( 0, 165-a/8, "Do not say forever;");
u8g.drawStr( 0, 176-a/8, "Do not");
u8g.drawStr( 0, 187-a/8, "meet tomorrow.");
u8g.drawStr( 0, 198-a/8, "And I see you never,");
u8g.drawStr( 0, 209-a/8, "I am virtue as snow.");
}
unsigned long draw_state = 0;
void draw(void) {
u8g_prepare();
switch(draw_state >> Con_interval) {
case 0 : u8g_print1 (draw_state); break;
}
}
void setup(void) {
u8g.setRot180();
}
void loop(void) {
u8g.firstPage();
do {
draw();
}
while( u8g.nextPage() );
draw_state++;
if ( draw_state >= Con_pages * pow(2,Con_interval))
draw_state = 0;
}
这就实现前一篇的功能了hhh
进入正题——arduino
arduino的编程跟c语言差别不大,所以并不会很难上手。我个人感觉差异主要在于:需要声名端口输入或输出,用函数而非赋值进行输入输出,可以直接使用analog输入和pwm输出,拥有串口监视器简便的进行串口通讯。以下详述。
基本框架
arduino有很明确的编程框架:
1.在开头引用头文件,做宏定义,声名全局变量,给管脚命名。
2.紧接着编写自己的函数
3.之后在setup()里进行管脚的初始化,以及串口的初始化
管脚初始化有以下的形式:
pinMode(pin1,INPUT); //初始化管脚为输入
pinMode(pin2,OUTPUT); //初始化管脚为输出
pinMode(pin3,INPUT_PULLUP)//初始化管脚为输入且启用上拉电阻
4.最后就是loop()循环执行主函数
数字输入输出
arduino的数字输出是通过函数。
digitalWrite(pin1,HIGH);
digitalWrite(pin2,LOW);
分别是输出高,低电平。
输入也是通过函数,函数返回值即为输入值(感觉说读取值好一点??)
key=digitalRead(pin);
analog输入
通俗的说就是能读取端口的电压值,之后表示为0-1023之间的数。
具体表示方法:返回值/1023=实际电压/标准电压(默认5v)
标准电压是可以设置的,在setup里调用函数analogReference(参数)
analogReference(DEFAULT); //默认电压值
analogReference(INTERNAL1V1); //1.1v
analogReference(INTERNAL2V56); //2.56v
analogReference(EXTERNAL); //AREF口外加电压
需要注意的是:当端口处于悬空状态(意思明白就好)时,读取到的电压可能为任意值
其实其他口也是这样,但这个特性对analog输入的影响更大。具体下文会提到。这里先把函数放出来
Value=analogRead(A0); //读取A0口的电压并赋值给Value
PWM输出
与analog相应的输出,实际上是通过调整高、低电平在一个周期里的所占总时间比例,实现将数字信号转换为模拟信号。(可以理解为输出0与5v之间的电压值??)
直接上代码了,这是一个9脚输出控制呼吸灯的程序。
int ledpin=9;
int brightness=0;
int fadeAmount=5;
void setup() {
pinMode(ledpin,OUTPUT);
}
void loop() {
analogWrite(ledpin,brightness);
brightness+=fadeAmount;
if(brightness==0||brightness>=255)
{
fadeAmount=-fadeAmount;
delay(100);
if(brightness==0)digitalWrite(ledpin,LOW);
delay(600);
}
delay(100);
}
其中analogWrite完成了PWM输出,其第二个参数应介于0-255之间,在这个程序中第二个参数brightness反映了亮度。
串口监视器
感觉arduino特别人性化的一点,就是功能整合的好,用起来方便。串口监视器就是其一。
要用的话需要在setup()里进行一个初始化。
Serial.begin(9600);
参数是波特率,波特率需要与电脑上所选择的波特率匹配
之后会用到的几个函数
Serial.print("xxxx"); //输出字符串
Serial.println(Value); //输出某个变量值并换行
Serial.available(); //判读有无输入,有则返回1,没有返回0
data=Serial.read(); //返回读到的一个字节数据
一个有bug的程序
看到书上有写到一个多按键的程序,不同的按键按下会导致A0口输入不同的电压值,从而用一个端口完成了多个按键的扫描。
于是小白有了如下的实践:
需要说明的是我在0-5v之间串联5个相同电阻,按键接在了两两电阻之间。按键的另一端共同接到A0
int Value;
void setup() {
pinMode(A0,INPUT);
Serial.begin(9600);
}
void loop() {
Value=analogRead(A0);
if(Value>202&&Value<205) Serial.println(Value);
else if(Value>408&&Value<412) Serial.println(Value);
else if(Value>613&&Value<616) Serial.println(Value);
else if(Value>817&&Value<821) Serial.println(Value);
delay(200);
}
当分别按下4个按键,在监视器里分别会看到4种值。
不过bug在于按键不按的时候A0口相当于悬空,可能返回任意值,就有可能凭空触发按键的程序,而A0口接在vcc或者gnd都会影响按键的扫描,导致按下没有效果。。
不知道这个bug有什么办法解决。我统计了5分钟内“凭空触发”的次数,如下:
5分钟这么多次还是不少的……所以看来这个暂且还不能作为一个操作按键的方法,还希望有大佬来指点迷津一些。
今天内容就这些了,鄙人不才,告辞。