เรียนรู้และฝึกทดลองไปกับบอร์ดไมโครคอนโทรเลอร์ STM32 Nucleo จากค่าย STMicroelectronics (ตอนที่ 7 ทดลองใช้งานพอร์ต SPI บนบอร์ด Nucleo)

เรียนรู้และฝึกทดลองไปกับบอร์ดไมโครคอนโทรเลอร์ STM32 Nucleo

จากค่าย STMicroelectronics

(ตอนที่ 7 ทดลองใช้งานพอร์ต SPI บนบอร์ด Nucleo)

    ในบทความนี้เป็นการทดลองเชื่อมต่ออุปกรณ์ผ่านพอร์ต SPI โดย SPI ย่อมาจาก Serial Peripheral Interface ใช้ขาสัญญาณ 4 เส้นคือ SLCK (Serial Clock), MOSI (Master Output Slave Input), MISO (Master Input Slave Output) และ SS (Slave Select) พอร์ต SPI บนบอร์ด Nucleo F401RE มีอยู่ 4 พอร์ต ในตัวอย่างนี้เขียนโปรแกรมใช้ Nucleo อ่านค่าจาก ESEN265 TSL2561 Lux Sensor และนำค่าที่อ่านได้ไปวาดกราฟบนหน้าจอ EFDV265 2.8” TFT Touch Shield V2.0 โดยใช้พอร์ต SPI ที่ 1 ใช้ขาดังนี้

ภาพไดอะแกรมการต่อ Nucleo เข้ากับ ESEN265 TSL2561 Lux Sensor และหน้าจอ EFDV265 2.8” TFT Touch Shield V2.0 จะเห็นได้ว่าในบอร์ด Shield หน้าจอ TFT ประกอบด้วยหน้าจอ SD Card ที่ต่ออยู่บน SPI Bus เดียวกัน และ Touch Screen ที่ต่อเข้าที่ขา ADC ในตัวอย่างนี้จะทดสอบเฉพาะหน้าจอ TFT

 ก่อนใช้งาน Shield ให้บัดกรีที่จุดบัดกรี P1, P2, P3 เพราะโดยปกติ Shield จะใช้ขา SPI จากคอนเน็ตเตอร์ ICSP บนบอร์ด Arduino แต่ในกรณีของบอร์ด Nucleo ไม่มีคอนเน็ตเตอร์ ICSP ต้องใช้ขา SPI จากคอนเน็ตเตอร์ Pins Header ด้านข้างแทน

 จากนั้นสร้างโปรเจคโปรแกรมใหม่ชื่อ Nucleo_TFT และสร้างไฟล์โปรแกรม main.cpp พร้อมทั้งอิมพอร์ต mbed library

อิมพอร์ต Library เซ็นเซอร์ TSL2561 กดที่ import this library จากนั้นที่หน้า Import Library เลือก Target Path เป็นชื่อโปรเจคโปรแกรม และกดปุ่ม Import เหมือนกับการทดลองที่แล้ว 

 เข้าไปในหน้าเว็บ Library ของ 2.8” TFT Touch Shield V2.0 เลือก Target Path เป็นชื่อโปรเจคโปรแกรม และกดปุ่ม Import

เมื่ออิมพอร์ต Library ทั้งหมดแล้ว หน้าต่างใน Program workspace จะได้ดังภาพ

 เขียนโค้ดโปรแกรมใน main.cpp ดังนี้

#include "mbed.h"
#include "TSL2561_I2C.h"
#include "SeeedStudioTFTv2.h"
 
#define PIN_XP          A3
#define PIN_XM          A1
#define PIN_YP          A2
#define PIN_YM          A0
#define PIN_MOSI        D11
#define PIN_MISO        D12
#define PIN_SCLK        D13
#define PIN_CS_TFT      D5
#define PIN_DC_TFT      D6
#define PIN_BL_TFT      D7
#define PIN_CS_SD       D4
 
SeeedStudioTFTv2 TFT(PIN_XP, PIN_XM, PIN_YP, PIN_YM, PIN_MOSI, PIN_MISO, PIN_SCLK, PIN_CS_TFT, PIN_DC_TFT, PIN_BL_TFT, PIN_CS_SD);
TSL2561_I2C lux_sensor( I2C_SDA, I2C_SCL );
Serial pc(SERIAL_TX, SERIAL_RX);
 
int point_x_new=0;
int point_x_old=0;
int point_y_old=0;
float value_lux =0;
 
int map(int x, int in_min, int in_max, int out_min, int out_max)
{
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
 
void graph_setpoint(int value)
{
    point_x_new +=8;
    value=map(value,0,20,0,240);
    TFT.line(point_y_old,point_x_old,value,point_x_new,Red);
    point_x_old = point_x_new;
    point_y_old = value;
    if(point_x_old == 320) {
        point_x_old = 0;
        point_x_new = 0;
        value_lux =0;
        TFT.cls();
    } //end if
}
 
 
int main()
{
    TFT.background(Black);
    TFT.foreground(White);
    TFT.cls();
    lux_sensor.enablePower();
    while(1) {
        value_lux = lux_sensor.getLux();
        pc.printf("Lux: %4.2f\r\n",value_lux);
        graph_setpoint((int)value_lux);
        wait_ms(500);
    }
}

 จากโค้ดโปรแกรมจะเห็นได้ว่า

SeeedStudioTFTv2 TFT(PIN_XP, PIN_XM, PIN_YP, PIN_YM, PIN_MOSI, PIN_MISO, PIN_SCLK, PIN_CS_TFT, PIN_DC_TFT, PIN_BL_TFT, PIN_CS_SD);
TSL2561_I2C lux_sensor( I2C_SDA, I2C_SCL );
Serial pc(SERIAL_TX, SERIAL_RX);

  ประกาศ object SeeedStudioTFTv2 ชื่อ TFT กำหนดขาจากที่ define ไว้ ประกาศ object TSL2561_I2C ชื่อ lux_sensor ใช้พอร์ต I2C ที่ 1 และใช้งาน Serial ที่ 2 จากขา D0, D1 

int map(int x, int in_min, int in_max, int out_min, int out_max)
{
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

  สร้างฟังก์ชัน map สำหรับกำหนดข้อมูลน้อยและมากที่สุดใหม่ตามค่า parameter ที่กำหนด

void graph_setpoint(int value)
{
    point_x_new +=8;
    value=map(value,0,20,0,240);
    TFT.line(point_y_old,point_x_old,value,point_x_new,Red);
    point_x_old = point_x_new;
    point_y_old = value;
    if(point_x_old == 320) {
        point_x_old = 0;
        point_x_new = 0;
        value_lux =0;
        TFT.cls();
    } //end if
}

  สร้างฟังก์ชัน graph_setpoint สำหรับวาดกราฟ ใช้ฟังก์ชั่น map เพื่อกำหนดค่าที่อ่านได้ แปลงให้เหมาะสมกับความกว้างของหน้าจอ คือไม่เกิน 240 จากนั้นใช้คำสั่ง TFT.line กำหนดจุดเริ่มต้น จุดสิ้นสุดของเส้น และสีของเส้น เก็บจุดสิ้นสุดของเส้นปัจจุบันไว้ เพื่อเป็นจุดเริ่มต้นให้กับเส้นใหม่ ถ้าตรวจสอบได้ว่าค่าที่แกน x เท่ากับขนาดความกว้างของหน้าจอ (320) ให้ Clear หน้าจอและเซตค่าทั้งหมดเป็น 0

int main()
{
    TFT.background(Black);
    TFT.foreground(White);
    TFT.cls();
    lux_sensor.enablePower();

  ในฟังก์ชั่น main กำหนดค่าสีที่ background และ foreground และ Clear หน้าจอ จากนั้นเริ่มให้เซนเซอร์ทำงาน 

while(1) {
        value_lux = lux_sensor.getLux();
        pc.printf("Lux: %4.2f\r\n",value_lux);
        graph_setpoint((int)value_lux);
        wait_ms(500);
    }

จากนั้นวนอ่านค่าทุกๆ 500 ms โดยใช้คำสั่ง lux_sensor.getLux(); ส่งค่าที่อ่านได้ไปยัง PC ผ่านพอร์ต Serial 2 และใช้วาดกราฟผ่านฟังก์ชั่น graph_setpoint();
           หลังจากที่โหลดโปรแกมที่บอร์ด mbed แล้วทดลองโปรแกรมโดยเปิดโปรแกรม X-CTU แสดงข้อความที่ Nucleo ค่าอ่านจาก Lux Sensor ส่งกลับมาที่ PC และกราฟที่แสดงหน้าจอ TFT