嵌入式编程


小组作业

个人作业

学习成果:

你是否:

本周工作流程

第 8 周工作流程图


使用的工具


使用的软件


小组作业

去看小组作业页面

简介

阅读数据手册

几点感想:

说正经的,我真的觉得这是最难的作业之一。我被这份数据手册卡住了。

我打算直接跳到编程部分,数据手册只拿来查阅。同时,我会在下面标出重要的章节:

ATTINY44A 引脚配置 ATTINY44A 引脚配置


编程

因为我当时有点搞不清该怎么做,就决定把每一步都详细列出来,给接下来的项目留个模板。适用的时候,我会在每一步之后填上空白,边做边写文档,下面就是结果:

  1. 烧录引导程序(bootloader)
    1. 确定编程器

      - avrdude 或 Atmel Studio 7 (仅 Windows)

    2. 确定引导程序和 makefile

      - 为此,我先说明我要编程的是 ATTINY44A

      - 下载 makefile

      - 这里不会用到引导程序,因为没有 USB

    3. 下载引导程序

      - 不适用

    4. 确定烧录引导程序的命令

      - 没有

    5. 烧录引导程序(bootloader)

      - 没有


  2. 烧录固件
    1. 确定示例代码:

      - 这是代码,来自 Neil 教授

    2. 确定编译和烧录固件的命令

      - 把之前下载的所有文件放在同一个文件夹里,在 Linux 下我把文件重命名为 makefile,然后运行脚本生成固件(每次想改代码我都会重复这一步):

      mv hello.ftdi.44.echo.c.make makefile
      make

      重命名为 makefile 并编译 重命名为 makefile 并编译

    3. 编译源代码

      - 在上一步已完成

    4. 让 makefile 适配我的编程器

      编辑 makefile 以适配编程器 我得编辑 makefile 才能配合我的编程器。做法是把 usbtiny 这一项换成 USBasp,一共改 2 次,一次用于烧录固件,一次用于烧录熔丝位(fuses)

    5. 烧录固件

      运行:

      make program-usbasp

      烧录固件 烧录固件

    6. 确定要烧录哪些熔丝位

      - 这在 makefile 里已经做好了

    7. 烧录熔丝位

      运行:

      make program-usbasp-fuses

      烧录熔丝位 烧录熔丝位


用 Arduino IDE 编程

我也决定试试用 Arduino IDE 给我的电路板编程。

为此,有几个步骤在任何操作系统上都应该适用

  1. 在开发板管理器里添加一块新开发板:

    把下面这段粘贴到(首选项)中的(附加开发板管理器网址:)

    https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json

    在 Arduino IDE 里添加开发板

  2. 选择你刚添加的开发板,我这里是 ATtiny44

    选择 ATtiny44 开发板

  3. 选择处理器,和前面一样

    选择处理器

  4. 选择时钟。因为我用的是 20 MHz 外部晶振,所以选了“External 20 MHz”

    选择时钟

  5. 因为我想在这块板上做一点串口监视,所以选了和我的 FTDI 对应的选项,也就是“/dev/cu.usbserial-A7032T9C”

    选择串口

  6. 编译和烧录之前的最后一步是选择编程器,我这里是“USBasp”

    选择编程器


第一次测试

烧录 Neil 的代码 “hello.ftdi.44.echo.c”

这里我没有用终端和 avrdude,而是用了 Arduino IDE,因为它自带串口监视器。

结果都在视频里


编写别的程序

现在我要试试让电路板在我按下按钮时闪起来。

  1. 找出按钮接在哪个引脚上

    电路板原理图

    看了电路板的原理图,我发现按钮接在引脚 10 上

  2. 找出 LED 接在哪个引脚上

    看了电路板的原理图,我发现 LED 接在引脚 6 上

  3. 代码

    用大白话说,我想要这样的效果:

    1. 等待按钮
    2. 如果按钮被按下,就让 LED 闪 3 次
    3. 如果没有,就回到开头

问题是我从来没有真正从零写过代码,只是改过代码,所以这会是个挑战……


第 1 次迭代

我是怎么做的

我先试着把 Arduino IDE 的 Blink 代码 改成我的引脚编号。没成功

下面是不含注释的代码:

void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  
}

void loop() {

  digitalWrite(LED_BUILTIN, HIGH);   
  delay(1000);                       
  digitalWrite(LED_BUILTIN, LOW);    
  delay(1000); 
  
}

第一段代码没成功,因为我用的是给 Arduino 平台写的代码,却跑在我自己做的板子上。Arduino 板通常有一个接在引脚 13 上的板载 LED,我的板子没有!Arduino 平台给板载 LED 用的常量是:

LED_BUILTIN 

第一段代码里我试着用这个常量,没成功。第二段代码里我通过尝试发现,把常量换成一个数字就能让 LED 亮起来。

ATtiny44 正确的代码需要在开头用下面这行代码声明引脚:

const int ledPin =  07;

我是在反复试错中才明白这一点的。现在我知道了,数据手册上的引脚编号和 Arduino 的引脚编号并不对应,而 Arduino 的引脚编号也和 Arduino 平台的常量不一样。当然,这毕竟是块定制板,但这就是当小白的代价!

于是,在试出正确的引脚编号之后,我给板子写了程序,成功让它闪起来了!

下面是去掉注释的定制代码:

const int ledPin =  07;

void setup()    {

  pinMode(ledPin, OUTPUT);
  
}

void loop()     {

  digitalWrite(ledPin, HIGH);
  delay(1000);
  digitalWrite(ledPin, LOW);
  delay(1000);

}
        

不用再靠试错找引脚了。下面是 ATtiny44 在 Arduino 上的引脚图

ATtiny44 的 Arduino 引脚图

为了让板子识别按钮,我也需要初始化它,在 sketch 开头加上下面这行代码:

const int buttonPin = "the pin number here"

接下来我得声明一个变量来保存引脚状态,代码如下:

int buttonState = 0; 

上面代码里的 <0> 也可以写成 <LOW>,这是 Arduino 编程里的另一个常量。关于常量可以看 Arduino 网站。

查过 ATtiny44 在 Arduino 上的引脚、手里有了正确的引脚编号之后,我把代码里的引脚换掉,就成功了!这里是代码。 (后来更正:原文件里写的是 if (buttonState, HIGH),而且大括号位置不对,编译不过。)

const int buttonPin = 3;
const int ledPin =  7;

int buttonState = 0; 

void setup() {

  pinMode(ledPin, OUTPUT);

  pinMode(buttonPin, INPUT);
}

void loop() {

  buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH) {

  digitalWrite(ledPin, HIGH);
  } else {

    digitalWrite(ledPin, LOW);
  }
}
    
原理图

因为很多年前我把这块板弄丢了,所以我只能展示怎么在一块类似的板子上连接编程器,就像我在电子设计周做的那样。

编程器 FabISP 和 USBasp

这里我展示怎么在输出设备里使用这些编程器。不用 Arduino IDE 的另一种方法,请看嵌入式编程

USBasp 编程器USBasp

用我做的 FabTinyISP 或 USBtinyISP,通过 Arduino IDE 给一块 ATtiny44 板编程。

FabISP 编程器FabISP

要改变按钮的行为,我只需把常量 <HIGH> 换成 <LOW>,就在这里:

if (buttonState == LOW) {

这样代码的逻辑就反过来了,也就是说按钮松开时 LED 是灭的。

现在我把 LED 亮和灭的时机反过来了。这里是去掉注释的代码:

const int buttonPin = 3;
const int ledPin =  7;

int buttonState = 0;

void setup() {

  pinMode(ledPin, OUTPUT);

  pinMode(buttonPin, INPUT);
}

void loop() {

  buttonState = digitalRead(buttonPin);

  if (buttonState == LOW) {

    digitalWrite(ledPin, HIGH);   
  }else {

    digitalWrite(ledPin, LOW);
    }
    }

我们来看证据……


闪 3 次

在代码里简单加一点东西,我就把行为改成了闪 3 次。

闪 3 次的代码下载代码 (后来更正:原来的循环只是三次把 LED 点亮,没有熄灭,所以它从来没有闪过;现在它会在两次闪烁之间熄灭并等待。图片显示的是原始代码。)


改造电路板

我有点不爽,因为我的板子通电时不会告诉我,所以我决定焊一个红色 LED 和一个 22 欧姆的电阻,这样如果我接错了,我就能知道并换过来。(注:在 5 V 下,22 欧姆会让大约 145 mA 流过 LED,远远超过它能承受的 20-30 mA;正确的大约是 150 欧姆。)

下面是改造前和改造后

改造前的电路板 之前

改造后的电路板 之后

改造后点亮红色 LED 的电路板 之后

← (3月18日) 计算机控制加工 · 所有周 · 输入设备 (4月1日) →