【格院】基于STM32L432KC之入坑MS Lab Part 3

一、做实验!

2.1、Exercise 6

看题目要求

Exercise 6 - Creating constant output voltages
a.Given the description of the range of analogue voltages that the mbed can output, what are the two output voltages that should appear on pin A4?
b. Confirm the two output voltages in the code shown above are as you expect.
c. Modify the code to output constant voltages of 0.5 V, 1.0 V, 2.0 V and 2.5 V.

本次实验相对简单在这个实验中,我们会第一次接触到模拟输出:

代码功能
AnalogOut Aout(A4);模拟输出,通过控制与高电平的比例来控制该引脚输出的电压

如示例:

/*Program to output 2 voltage levels to analogue-pin 4 Read the output on a multimeter
 */
#include "mbed.h"
AnalogOut Aout(A4); // create an analogue output on analogue-pin 4
int main()
{
    while (1)
    {
        Aout = 0.33;
        thread_sleep_for(2000);
        Aout = 0.66;
        thread_sleep_for(2000);
    }
}

这里的0.33表示输出0.33*3.3V=1.1V的电压。而对于题目,只需要计算出各个电压对应的占比即可。

注:DAC相当于就是把3.3v的电压分成n份,假设是10,那么一份的电压就是0.33V,也就是精度为0.33V,这个时候让他输出0.5V是没办法的,他只能用两个0.33V也就是0.66V来近似。但是当我们的精度足够高,比如每一份是1/(210),那我们可以近似的电压就多了很多,输出可以近似看成模拟信号。(这里建议大家结合PPT一起理解)

2.2、Exercise 7

Exercise 7 - Creating a sawtooth waveform
a. Using a for loop, generate a 100 Hz sawtooth waveform with minimum and maximum voltages of 0 V and 3 V, respectively. You will have to work out how many “steps” to have in your sawtooth and then calculate their duration so that the frequency is correct.
b. Measure the output signal using an oscilloscope. Determine the frequency of the sawtooth waveform.
c. Change the time scale on the oscilloscope so that you can see the individual steps that form the sawtooth. Are the steps in voltage of uniform magnitude? Is the increment equal to the step size that you calculated in part a?
Hint: Read the mbed datasheet to determine the number of bits that the digital-to-analog converter (DAC) has.
Note: Not all components in a microcontroller (microprocessor) are composed of digital logic gates. A DAC and its complement, an analogue-to-digital converter (ADC) contain analogue circuits.

这题要求我们输出一个锯齿波。先看看锯齿波长啥样:
在这里插入图片描述
这样的锯齿波每时刻电压值都在变化,考虑使用模拟输出AnalogOut;同时注意到波形成周期性变化,可以用for循环;
这里的锯齿形可以看成是由一级一级很小时间的不断增加的电压拼接而成,类似于楼梯,对于固定长度的楼梯,只要不断增加楼梯阶数,就可以近似得到一段斜坡。

#include "mbed.h"

// main() runs in its own thread in the OS
AnalogOut ang_wave(A3);
int main()
{
    while (1) {
        for (float i=0.885; i>=0; i-=0.01) {
        ang_wave=i;		//电压值不断递增
        wait_us(95);	//保持状态95微秒
        }
    }
}

值得注意的是,题干中要求输入0~3V、100kHz的波,因此我这里选用从0.885变化到0,每次步进0.01。这里可以根据实际情况,不断测试,选用最合适的值。
同样,因为计算电压及输出需要时间,所以wait_us()的时间不一定准确,需要适当微调。
注:考虑到我们这块板使用12位DAC,最小步进为3.3V/(2^12)=0.8mV,所以步进值不能无限减小。
拓展:运用这种方法,我们可以尝试使示波器输出正弦波,其值可以考虑使用泰勒展开式进行近似。

2.3、Exercise 8

在这个实验中,我们要使用电位器(potentiometer)。这可以看成初高中使用的滑动变阻器,只不过是通过转动来控制电阻。中间的针脚代表滑片。

Exercise 8 – Illuminating LEDs depending on analogue input voltage
A simple way to observe the operation of the analogue input is to use a potentiometer to vary the drive voltage being applied to an LED. Figure 9 shows a potentiometer connected to an analogue input of the mbed (A6). The analogue input voltage can be used to directly drive the drive analogue output voltage of A4, which is connected to an LED. The potentiometer is just acting as a voltage divider – the resulting voltage will change the brightness of the LED.

我们在这个实验中需要使用电位器来控制灯的亮度。电位器可以控制滑片对应引脚与其他引脚之间的电压,而当我们将这个变化的电压给到LED时,便可以控制亮度了。
展示代码:

#include "mbed.h"
int main()
{
    AnalogOut output(A4);
    AnalogIn input(A6);
    while (1)
    {
        output = input;
    }
}

第一部分相对简单,我们再来看看第二部分。
这一部分需要我们通过电位器控制4个LED的开关:

Connect 4 separate LEDs at 4 digital output pins of the mbed. Write a program that will illuminate the 4 LEDs depending on the value of input voltage that is produced using a potentiometer to divide the output voltage on the Vout pin of the mbed. The LED illumination in response to the input voltage should meet the requirements in the table below.

VoltageLED1LED2LED3LED4
0 V< Vin <0.6 V0000
0.6 V< Vin <1.2 V1000
1.2 V< Vin <1.8 V1100
1.8 V< Vin <2.4 V1110
Vin >2.4V1111

这里我们这样分析:整个电路中自变量为电位器控制的电压,因变量为4个LED的亮灭。我们只需要检测这个电压值,之后使用 if 语句控制灯的亮灭。
这里电位器接AnalogOut,4个LED分别接入一个DigitalOut。
代码如下:

#include "mbed.h"
int main()
{
    DigitalOut led1(D4);
    DigitalOut led2(D5);
    DigitalOut led3(D9);
    DigitalOut led4(D11);
    AnalogIn test(A6);
    while (1)
    {
        if (test <= 0.18)	//0 ~ 0.6V
        {
            led1 = 0;
            led2 = 0;
            led3 = 0;
            led4 = 0;
        }
        if (0.18 <= test && test < 0.35)	//0.6V ~ 1.2V
        {
            led1 = 1;
            led2 = 0;
            led3 = 0;
            led4 = 0;
        }
        if (0.35 <= test && test < 0.54)	//1.2V ~ 1.8V
        {
            led1 = 1;
            led2 = 1;
            led3 = 0;
            led4 = 0;
        }
        if (0.54 <= test && test < 0.70)	//1.8V ~ 2.4V
        {
            led1 = 1;
            led2 = 1;
            led3 = 1;
            led4 = 0;
        }
        if (test >= 0.70)	// >2.4V
        {
            led1 = 1;
            led2 = 1;
            led3 = 1;
            led4 = 1;
        }
    }
}

这里的0.18、0.35等分别是各个临界电压对应的百分比。为保证更加精确,可以有适当微调。

2.4、Exercise 9

终于来到MS最后也是最难的实验啦!在这个实验中,我们需要使用SPI通信协议进行两块MCU板之间的交流。

Exercise 9 – Communication between MCU boards via SPI link
Communications systems are important for exchanging information. On the MCU board, there are various means of communication. Here we will investigate the SPI communication between two MCU boards: one MCU is set as ‘master’ (the controller issuing commands), and the other is set as the ‘slave’ (following commends). You will work in teams so you could use two MCU boards.
We use the SPI output/input on pins A6, A5 and A4. In addition, we need a digital line to select the slave that we wish to talk to, using pin D3. Connect each of these pins directly from one MCU to the same pin on the other. There should be 4 signal wires and a ground connection between the two breadboards.
Each MCU needs two switches and two LEDs, connected to the appropriate digital I/O pins. The switches from the master are used to control the LEDs on the slave and vice versa.

虽然说SPI协议到大二才会学,现在只需会用即可,但个人还是建议先上网查找资料,了解SPI的具体工作原理,有助于更好地理解代码。
这里推荐 一文搞懂SPI通信协议(不脱发的程序猿)。文图并茂,易于理解。
下面来解释一下代码
先是主机 (master) 程序

#include "mbed.h"
SPI ser_port(D11, D12, D13); // 分别定义输入输出线及时钟线
DigitalOut red_led(D5);      // red led
DigitalOut green_led(D4);    // green led
DigitalOut cs(A3);           // 用于选择与哪个从机通信
DigitalIn switch_ip1(A6);	// 检测控制LED1开关的开闭情况
DigitalIn switch_ip2(A7);	// 检测控制LED2开关的开闭情况
char switch_word; // 存储发送字符
char recd_val;    // 返回值
int main()
{
    while (1)
    {
        switch_word = 0xA0; // 设定一个初始值(1010 0000)
        if (switch_ip1 == 1)
            switch_word = switch_word | 0x01; // 如果开关1闭合,将第一位改为1(1010 0000->1010 0001)
        if (switch_ip2 == 1)
            switch_word = switch_word | 0x02;   // 如果开关2闭合,将第二位改为1(1010 0000->1010 0010; 1010 0001->1010 0011)
        cs = 0;                                 // 拉低电平,开始通信
        recd_val = ser_port.write(switch_word); // 将switch_word发送给recd_val(开关闭合的信息)
        cs = 1;	//拉高电平,停止通信
        thread_sleep_for(10);	//等待10ms
        red_led = 0; // 初始化灯的情况
        green_led = 0;
        recd_val = recd_val & 0x03; // 去掉开头的含1部分(1010 0000->0000 0000)
        if (recd_val == 0)	// 0000 0000=0
        {
            red_led = 0;
            green_led = 0;
            thread_sleep_for(500);
        }
        if (recd_val == 1)	// 0000 0001=1
        {
            red_led = 1;
            green_led = 0;
            thread_sleep_for(500);
        }
        if (recd_val == 2)	// 0000 0010=2
        {
            red_led = 0;
            green_led = 1;
            thread_sleep_for(500);
        }
        if (recd_val == 3)	// 0000 0011=3
        {
            red_led = 1;
            green_led = 1;
            thread_sleep_for(500);
        }
    }
}

其实真正的通信部分很少(只有三行),更重要的是其他过程;
再来看从机代码(slave):

#include "mbed.h"
SPISlave ser_port(D11, D12, D13, A3); // mosi, miso, sclk, ssel
DigitalOut red_led(D5);               // red led
DigitalOut green_led(D4);             // green led
DigitalIn switch_ip1(A6);
DigitalIn switch_ip2(A7);
char switch_word; // word we will send
char recd_val;    // value from master
int main()
{
    while (1)
    {
        // Set up the word to be sent, by testing switch inputs
        switch_word = 0xA0; // set up a recognisable output pattern
        if (switch_ip1 == 1)
            switch_word = switch_word | 0x01; // OR in lsb
        if (switch_ip2 == 1)
            switch_word = switch_word | 0x02; // OR in lsb
        if (ser_port.receive())
        {                                // test if data has been transmitted
            recd_val = ser_port.read();  // read byte from master
            ser_port.reply(switch_word); // make this the next reply
        }
        // set leds according to incoming word from slave
        red_led = 0; // preset both to 0
        green_led = 0;
        recd_val = recd_val & 0x03; // AND out unwanted bits
        if (recd_val == 0)
        {
            red_led = 0;
            green_led = 0;
            thread_sleep_for(500);
        }
        if (recd_val == 1)
        {
            red_led = 1;
            green_led = 0;
            thread_sleep_for(500);
        }
        if (recd_val == 2)
        {
            red_led = 0;
            green_led = 1;
            thread_sleep_for(500);
        }
        if (recd_val == 3)
        {
            red_led = 1;
            green_led = 1;
            thread_sleep_for(500);
        }
    }
}

从机代码与主机大体相近,只是注意在通信处有一个回答reply函数。
另外,我们查找mbed针脚图后会发现,支持SPI协议的有三组(SPI1: (D2, D3,D10), (A1, A4, A5); SPI3: (D11, D12, D13))。这里任选一组即可。
注:对于开关,如果你始终发现使用开关模块有问题,大概率是虚接的问题。你当然可以学习解决它, 但更简单的方法是直接使用两根线,接上便是闭合,不接便是断开,断开时只需要将连接DigitalIn的那一端接地即可正常工作。

二、小结

MS中的实验有些固然有难度,但如果经过自己的思考后做出来,便会其乐无穷!

三、参考资料

1、微信公众号:格院生存指南 / MS LAB | Part 2
2、 一文搞懂SPI通信协议(不脱发的程序猿)

  • 14
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值