KC225 - Bài giảng full

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 203

Lập trình điều khiển trên thiết bị di động

Programming and controlling on mobile device


KC225

Dr. Nguyễn Văn Khanh


BM Tự động hóa
Khoa Công nghệ - ĐH Cần Thơ
Email: vankhanh@ctu.edu.vn

1
Giới thiệu học phần

vankhanh@ctu.edu.vn 2
Mục tiêu học phần

vankhanh@ctu.edu.vn 3
Chuẩn đầu ra (CĐR) học phần

vankhanh@ctu.edu.vn 4
Đánh giá học phần

❑ Giữa kỳ: Trắc nghiệm ngắn Điểm danh theo buổi;


vắng quá 80% sẽ bị cấm thi
▪ Đánh giá Kiến thức (CO1...CO3),
▪ Một phần Kỹ năng (CO4, 5): Lập trình C nhúng trên SoC ESP32, App Android
❑ Bài tập nhóm: Báo cáo vào tuần cuối
▪ Đánh giá CO 4, 5, 6, 7: Thực hiện một App Android theo nhóm, bắt đầu từ tuần 1
❑ Kết thúc học phần: đánh giá các CO như giữa kỳ nhưng sâu hơn
vankhanh@ctu.edu.vn 5
Tài liệu

❑ Sử dụng slide do GV cung cấp


❑ Tài liệu theo đề cương: tìm dựa vào Số đăng ký cá biệt như trong bảng
❑ Các nguồn tài liệu trên Internet: Cung cấp theo nội dung

vankhanh@ctu.edu.vn 6
Nội dung
• Giới thiệu học phần
• ESP8266/ESP32: Kiến trúc và lập trình
• MIT App Inventor
• Các bước tạo ứng dụng
• Lập trình
• Một số ví dụ
• Lập trình điều khiển sử dụng Bluetooth
• Giới thiệu về chuẩn bluetooth
• Lập trình giao tiếp bluetooth sử dụng ESP32
• Xây dựng App
• Lập trình điều khiển sử dụng Wifi
• Giới thiệu về chuẩn Wifi
• Embedded Web Server
• Xây dựng App
vankhanh@ctu.edu.vn 7
Nội dung 1: Lập trình ESP32
❑ Nắm được kiến trúc và các thông số cơ bản của ESP32 SoC
❑ Cài đặt được compiler GCC và lập trình cho ESP32 sử dụng ESP-IDF Eclipse
❑ Hiểu và ứng dụng được một số hàm API trong các thư viện cơ bản của ESP32 như:
▪ GPIO - General Purpose Input/Output
▪ PWM - Pulse-width modulation
▪ ADC - Analog-to-digital converter
▪ I2C - Inter-Integrated Circuit

vankhanh@ctu.edu.vn 8
Espressif Systems
❑ Công ty bán dẫn thành lập năm 2008, có văn phòng tại China, Czech Republic, India,
Singapore và Brazil
❑ Định hướng ứng dụng Wi-Fi-and-Bluetooth, low-power, AIoT solutions
❑ SoC: ESP8266, ESP32, ESP32-S và ESP32-C, các module và các mạch phát triển ứng
dụng
❑ Cho phép các nhà phát triển sử dụng các giải pháp của Espressif để thiết kế các thiết bị
kết nối thông minh bởi giải pháp và công nghệ mã nguồn mở của họ

ESP32-DevKitC ESP8266-DevKitC 9
vankhanh@ctu.edu.vn
ESP32

ESP32 kit

vankhanh@ctu.edu.vn
Kích thước Pinout 10
ESP32 SoC
❑ Bộ xử lý Xtensa® LX6 2 nhân, xung
nhịp tối đa 240MHz / 600 MIPS

❑ Sử dụng công nghệ TSMC ultra-low-


power 40 nm

❑ 448 KB ROM

❑ 520 KB SRAM

❑ 16 KB SRAM in RTC

❑ Supports multiple flash/SRAM chips


https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf 11
vankhanh@ctu.edu.vn
ESP32 SoC
❑ Wifi:
▪ 802.11 b/g/n
▪ 802.11 n (2.4 GHz), up to 150 Mbps

❑ Bluetooth v4.2 BR/EDR and BLE

❑ 34 × programmable GPIOs

❑ 12-bit SAR ADC up to 18 channels

❑ 2 × 8-bit DAC

❑ 2 × I²C

❑ LED PWM up to 16 channels

vankhanh@ctu.edu.vn 12
Applications

vankhanh@ctu.edu.vn 13
NodeMCU-32S Kit

vankhanh@ctu.edu.vn 14
ESP SoC

vankhanh@ctu.edu.vn 15
Compiler - IDE
IDE – Integrated Development Environment

MicroPython

C/C++
vankhanh@ctu.edu.vn 16
Cài đặt/Installation
Link: https://docs.espressif.com/projects/esp-
idf/en/latest/esp32/get-started/#installation-step-by-step

Tool: https://dl.espressif.com/dl/esp-idf/?idf=4.4

vankhanh@ctu.edu.vn 17
Eclipse setup
>> Help / Install New Software...

Chọn: All Avai...

Chọn và cài tất cả các


software của Espressif IDF

vankhanh@ctu.edu.vn 18
ESP-IDF Tools Installation

vankhanh@ctu.edu.vn 19
Hello world application >> File / Espressif IDF Project

vankhanh@ctu.edu.vn 20
Application Template

Chọn các code mẫu được tích hợp


sẵn, đây cũng là các ví dụ kèm
theo khi cài đặt gói ESP-IDF

vankhanh@ctu.edu.vn 21
Port configuration
Cấu hình cổng COM nạp chương trình cho ESP32,
Cấu trúc ứng dụng driver mạch USB-COM phải được cài đặt

Số hiệu cổng tùy


từng máy cụ thể

vankhanh@ctu.edu.vn 22
Build Application

Build

Biên dịch
thành công

vankhanh@ctu.edu.vn 23
Run Application
 Click
Run

 Ấn giữ
phím Boot

Có thể nhả phím Boot


khi bắt đầu ghi

Nạp và chạy chương


trình thành công

vankhanh@ctu.edu.vn 24
Result

Kế quả của bạn thế nào?

vankhanh@ctu.edu.vn 25
GPIO API Functions
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)

esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)

esp_err_t gpio_set_level(gpio_num_t gpio_num,


uint32_t level)

int gpio_get_level(gpio_num_t gpio_num)

Lưu ý: Các GPIO 34, 35, 36, 39 không thể sử dụng như digital output (checked)

vankhanh@ctu.edu.vn 26
GPIO API 1– Application programming interface
API: GPIO common configuration.
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)
Điều kiện: #include "driver/gpio.h"
Output: esp_err_t
Input: gpio_config_t *pGPIOConfig
ESP_OK Success
uint64_t pin_bit_mask GPIO_SEL_0 ... GPIO_SEL_39
ESP_ERR_INVALID_ARG Parameter error
gpio_mode_t mode GPIO_MODE_DISABLE,
GPIO_MODE_INPUT, gpio_config_t io_conf;
GPIO_MODE_OUTPUT, //disable interrupt
GPIO_MODE_OUTPUT_OD, io_conf.intr_type =
GPIO_MODE_INPUT_OUTPUT_OD, GPIO_PIN_INTR_DISABLE;
GPIO_MODE_INPUT_OUTPUT //set as output mode
gpio_pullup_t pull_up_en GPIO_PULLUP_DISABLE (0), io_conf.mode = GPIO_MODE_OUTPUT;
GPIO_PULLUP_ENABLE (1) //bit mask of the pins that you want to set
gpio_pulldown_t pull_down_en
io_conf.pin_bit_mask = GPIO_SEL_2;
gpio_int_type_t intr_type GPIO_INTR_DISABLE, //disable pull-down mode
GPIO_INTR_POSEDGE,
io_conf.pull_down_en = 0;
GPIO_INTR_NEGEDGE,
GPIO_INTR_ANYEDGE,
//disable pull-up mode
GPIO_INTR_LOW_LEVEL, io_conf.pull_up_en = 0;
GPIO_INTR_HIGH_LEVEL, //configure GPIO with the given settings
gpio_config(&io_conf); 27
vankhanh@ctu.edu.vn
API: GPIO set direction. GPIO API 2
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)
Điều kiện: #include "driver/gpio.h"
Input: gpio_num_t gpio_num, gpio_mode_t mode
GPIO_NUM_NC: -1
gpio_num_t gpio_num
GPIO_NUM_0 ... GPIO_NUM_39: 0-39
GPIO_MODE_DISABLE,
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
gpio_mode_t mode GPIO_MODE_OUTPUT_OD,
GPIO_MODE_INPUT_OUTPUT_OD,
GPIO_MODE_INPUT_OUTPUT

Output: esp_err_t
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error

gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT);
gpio_set_direction(GPIO_NUM_2, GPIO_MODE_INPUT);
vankhanh@ctu.edu.vn 28
API: GPIO set output level.
GPIO API 3
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)
Điều kiện: #include "driver/gpio.h"

Input: gpio_num_t gpio_num, uint32_t level


gpio_num_t gpio_num GPIO_NUM_NC: -1
GPIO_NUM_0 ... GPIO_NUM_39: 0-39
uint32_t level 0: Low
1: High

Output: esp_err_t
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error

gpio_set_level(GPIO_NUM_2, 1);
gpio_set_level(2, 0);

vankhanh@ctu.edu.vn 29
API: GPIO get input level GPIO API 4
int gpio_get_level(gpio_num_t gpio_num)
Điều kiện: #include "driver/gpio.h"

Input: gpio_num_t gpio_num


gpio_num_t gpio_num GPIO_NUM_NC: -1
GPIO_NUM_0 ... GPIO_NUM_39: 0-39

Output: int
0 Logic tại gpio_num bằng 0
1 Logic tại gpio_num bằng 1

int inValue;
inValue = gpio_get_level(GPIO_NUM_6);
inValue = gpio_get_level(6);

vankhanh@ctu.edu.vn 30
Delay (Tạo trễ)
API: Delay a task for a given number of ticks, one of API function of FreeRTOS
void vTaskDelay(const TickType_t xTicksToDelay)
Điều kiện: #include "freertos/FreeRTOS.h"
#include "freertos/task.h"

vTaskDelay Tạo thời gian trễ


xTickToDelay Thời gian cần trùy hoản, số nhịp hệ thống

Ví dụ: tạo trễ 500ms


const TickType_t xDelay = 500 / portTICK_PERIOD_MS;
vTaskDelay(xDelay)

vankhanh@ctu.edu.vn 31
LED blinking application
1. #include "freertos/FreeRTOS.h"
Mạch LED:
2. #include "freertos/task.h"
3. #include "freertos/queue.h"
4. #include "driver/gpio.h"

5. void app_main(void)
6. {
7. gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT);
8. int level = 0;
9. while (true) {
10. gpio_set_level(GPIO_NUM_2, level);
11. level = !level;
12. vTaskDelay(1000 / portTICK_PERIOD_MS);
13. }
14. }
Biên dịch, nạp chương trình và quan sát trạng thái của built-in LED
Thay đổi thời gian trễ, quan sát kết quả! 32
vankhanh@ctu.edu.vn
Interrupt – Ngắt
Một sự kiện ngẫu nhiên xảy ra khi bộ xử lý đang thực chương trình, bộ xử lý sẽ:
1) Lưu ngữ cảnh hiện tại, chuyển đến chương trình phục vụ ngắt ISR – Interrupt Servive Routine
2) Thực thi mã lệnh trong ISR (gọn-nhẹ)
3) Phục hồi ngữ cảnh quay về tiếp tục thực hiện chương trình chính

Các hàm xử lý ngắt GPIO:


esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
esp_err_t gpio_install_isr_service(int intr_alloc_flags)
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args)
esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num)
esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
vankhanh@ctu.edu.vn 33
Các hàm xử lý ngắt GPIO:
Interrupt (tt)
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)

gpio_int_type_t intr_type: Chọn sự kiện ngắt


GPIO_INTR_DISABLE (= 0) Cắm ngắt GPIO
GPIO_INTR_POSEDGE (= 1) Ngắt xảy ra tại cạnh lên
GPIO_INTR_NEGEDGE (= 2) Ngắt xảy ra tại cạnh xuống
GPIO_INTR_ANYEDGE (= 3) Ngắt xảy ra tại cạnh cả hai cạnh
GPIO_INTR_LOW_LEVEL (= 4) Ngắt xảy ra khi ngõ vào kích hoạt mức 0
GPIO_INTR_HIGH_LEVEL (=5) Ngắt xảy ra khi ngõ vào kích hoạt mức 1

vankhanh@ctu.edu.vn 34
Là cờ chỉ có hai trạng thái: có hoặc không Binary semaphore
Khi một tác vụ nhận semaphore nó sẽ chuyển sang trạng thái
chờ nếu trạng thái là không có
Hai tác vụ trên bin semaphore: (freertos/semphr.h)
1. xSemaphoreTake(): nhận semaphore 
2. xSemaphoreGive(): gửi semaphore Task

3. xSemaphoreTakeFromeISR(): nhận trong ISR xSemaphoreTake()

4. xSemaphoreGiveFromISR(): gửi trong ISR semaphore

Tác vụ bị khóa chờ semaphore


 Task
Ngắt, ISR
xSemaphoreGiveFromISR() xSemaphoreTake()
semaphore

Tác vụ được mở khóa để thực


thi mã lệnh tiếp theo

vankhanh@ctu.edu.vn 35
Task – Tác vụ
Là một building block của Hệ điều hành/Hệ điều hành nhúng
ESP-IDF tích hợp nhân hệ điều hành nhúng FreeRTOS
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, // Tên hàm thực hiện tác vụ
const char * const pcName, // Tên tác vụ, vd: "BtnTask"
configSTACK_DEPTH_TYPE usStackDepth, //Độ sau ngăn xếp lưu ngữ cảnh
void *pvParameters, // Tham số nếu có
UBaseType_t uxPriority, // Độ ưu tiên task, giá trị cao ưu tiên cao
TaskHandle_t *pxCreatedTask ); // handle của tác vụ (con trỏ)

/* Khung hàm của tác vụ */


void vTaskCode( void * pvParameters ) {
/* Khai báo biến <Sửa lại tên chương trình con cho khớp>
Khởi tạo tham số củ tác vụ */
int32_t counter; xTaskCreate( button_task,
bool led_status = false; "button_task",
for( ;; ) { 2048,
/* Mã lệnh thực thi tác vụ. */ NULL,
count++; 10,
led_status = !led_status; NULL);
gpio_set_level(GPIO_NUM_0, led_status);
vTaskDelay(100/portTICK_PERIOD_MS);
} Bị khóa 100ms trả CPU cho tác vụ khác chạy
}
vankhanh@ctu.edu.vn 36
Task (tt)
❑ Trên ứng dụng có thể chứa nhiều tác vụ, các tác vụ HĐH lập lịch sử dụng CPU dựa
vào độ ưu tiên
❑ Tác vụ có độ ưu tiên cao hơn sẽ chiếm CPU của tác vụ khác khi có nhu cầu
❑ Các tác vụ có cùng độ ưu tiên sẽ được phục vụ xoay vòng
❑ Độ ưu tiên là số nguyên từ 0 đến 32, giá trị lớn sẽ có độ ưu tiên cao hơn

❑ Tác vụ phải chuyển về trạng thái bị khóa khi không có nhu cầu sử dụng CPU.
❑ vTaskDelay(t/portTICK_PERIOD_MS): lệnh phổ biến để trả CPU
❑ xSemaphoreTake(), xSemaphoreTakeFromeISR(): Tác vụ sẽ bị khóa nếu cờ semaphore không sẵn có
❑ ...

vankhanh@ctu.edu.vn 37
Cấu hình ngắt cho GPIO:
// Tạo cờ binary semaphore
GPIO Interrupt processing
xSemaphore = xSemaphoreCreateBinary();

// Cấu hình GPIO Cài đặt tác vụ xử lý:


gpio_set_direction(GPIO_NUM_0, GPIO_MODE_INPUT); // Tác vụ xử lý khi phím ấn: mã lệnh gợi ý
gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); void button_Task(void* arg) {
// Cho phép ngắt tại cạnh xuống static int32_t counter;
gpio_set_intr_type(GPIO_NUM_0, GPIO_INTR_NEGEDGE); for( ; ;) {// lập vô định
// chờ semaphore từ ISR
// Tạo tác vụ xử lý ngắt if(xSemaphoreTake(xSemaphore,portMAX_DELAY)
xTaskCreate(button_Task, "buttonTask", 2048, NULL, 10, NULL); == pdTRUE) {
// in gia trị đếm
// Cài đặt dịch vụ ngắt mặc định ESP_LOGI(TAG,"Button pressed! %d", counter++);
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); // đảo trạng thái led
led_status = !led_status;
// Cấu hình handler gpio_set_level(GPIO_NUM_17, led_status);
gpio_isr_handler_add(GPIO_NUM_0, button_isr_handler, NULL); // xử lý dội phím ví dụ
gpio_intr_disable(GPIO_NUM_0);
Cài đặt ISR: while(!gpio_get_level(GPIO_NUM_0)){
vTaskDelay(5 / portTICK_PERIOD_MS);
void IRAM_ATTR button_isr_handler(void* arg) { }
// Tạo semaphore, kích hoạt buttonTask vTaskDelay(10 / portTICK_PERIOD_MS);
xSemaphoreGiveFromISR(xSemaphore, NULL); gpio_intr_enable(GPIO_NUM_0);
} }
}
Cần khai báo biến toàn cục: xSemaphore }
SemaphoreHandle_t xSemaphore = NULL;
vankhanh@ctu.edu.vn 38
MCPWM modules

MCPWM MCPWM
Unit A Unit B

- Thư viện hỗ trợ #include "driver/mcpwm.h"


- Các ngõ ra PWM có thể được cấu hình linh
hoạt đến tất cả các GPIO có hỗ trợ

vankhanh@ctu.edu.vn 39
PWM API Functions
1/ esp_err_t mcpwm_gpio_init( mcpwm_unit_t mcpwm_num,
mcpwm_io_signals_t io_signal,
int gpio_num)
2/ esp_err_t mcpwm_init( mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
const mcpwm_config_t *mcpwm_conf)
3/ esp_err_t mcpwm_set_duty(
mcpwm_unit_t mcpwm_num,
mcpwm_timer_t timer_num,
mcpwm_generator_t gen,
float duty)

vankhanh@ctu.edu.vn 40
API: This function initializes each gpio signal for MCPWM. PWM API 1
esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal, int gpio_num)
Điều kiện: #include "driver/mcpwm.h"

Input: mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal, int gpio_num


MCPWM_UNIT_0 (0): Unit 0
mcpwm_unit_t mcpwm_num
MCPWM_UNIT_1 (1): Unit 1
MCPWM0A: PWM0A output pin
MCPWM0B: PWM0B output pin
mcpwm_io_signals_t MCPWM1A: PWM1A output pin
io_signal MCPWM1B: PWM1B output pin
MCPWM2A: PWM0A output pin
MCPWM2B: PWM0B output pin
int gpio_num set this to configure GPIO for MCPWM, if you want to use gpio16, gpio_num = 16

Output: esp_err_t
ESP_OK Success Ví dụ:
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, 2);
ESP_ERR_INVALID_ARG Parameter error

vankhanh@ctu.edu.vn 41
API: Initialize MCPWM parameters
esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, PWM API 2
const mcpwm_config_t *mcpwm_conf)
Điều kiện: #include "driver/mcpwm.h"
Input: mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpwm_config_t *mcpwm_conf)
mcpwm_unit_t mcpwm_num MCPWM_UNIT_0 (0): Unit 0; MCPWM_UNIT_1 (1): Unit 1
MCPWM_TIMER_0: Select MCPWM timer0
mcpwm_timer_t timer_num MCPWM_TIMER_1: Select MCPWM timer1
MCPWM_TIMER_2: Select MCPWM timer2
uint32_t frequency Tần số xung PWM (Hz)
float cmpr_a Độ rộng xung của kênh A và B.
float cmpr_b Ví dụ: độ rộng 62.3%, truyền 62.3
struct mcpwm_config_t
mcpwm_duty_type_t duty_mode MCPWM_DUTY_MODE_0: Active high
*mcpwm_conf MCPWM_DUTY_MODE_1: Active low
mcpwm_counter_type_t MCPWM_UP_COUNTER
counter_mode MCPWM_DOWN_COUNTER
MCPWM_UP_DOWN_COUNTER (tần số bằng 1/2)

Output: esp_err_t
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error
vankhanh@ctu.edu.vn 42
PWM API 2 / Example

Ví dụ: Cấu hình tạo xung PWM tại chân GPIO2, Timer 0B, tần số 1 kHz, độ
rộng xung 5%

mcpwm_config_t pwm_config;
// PWM init
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, 2);
pwm_config.frequency = 1000; //frequency = 1000Hz
pwm_config.cmpr_a = 5.0; //duty cycle of PWMxb = 5.0%
pwm_config.cmpr_b = 5.0; //duty cycle of PWMxb = 5.0%
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
//Configure PWM0A & PWM0B with above settings
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);

vankhanh@ctu.edu.vn 43
API: Set duty cycle of each operator(MCPWMXA/MCPWMXB)
PWM API 3
esp_err_t mcpwm_set_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen, float duty)
Điều kiện: #include "driver/mcpwm.h"

Input: mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen, float duty


mcpwm_unit_t mcpwm_num MCPWM_UNIT_0 (0): Unit 0
MCPWM_UNIT_1 (1): Unit 1
mcpwm_timer_t timer_num MCPWM_TIMER_0: Select MCPWM timer0
MCPWM_TIMER_1: Select MCPWM timer1
MCPWM_TIMER_2: Select MCPWM timer2
mcpwm_generator_t gen MCPWM_GEN_A: Select MCPWMXA
MCPWM_GEN_B: Select MCPWMXB

Output: esp_err_t
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error

Ví dụ: mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_GEN_B,30.5);


vankhanh@ctu.edu.vn 44
LED brightness controlling application
#include "freertos/FreeRTOS.h"
#include "freertos/task.h" while (true) {
#include "driver/mcpwm.h" //Increase the brightness
void app_main(void) for (int i=0; i<100; i++){
{ mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0,
mcpwm_config_t pwm_config; MCPWM_GEN_B, i);
// PWM init vTaskDelay(10 / portTICK_PERIOD_MS);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, 2); }
//frequency = 1000Hz //Decrease the brightness
pwm_config.frequency = 1000; for (int i=0; i<100; i++){
//duty cycle of PWMxb = 0.0% mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0,
pwm_config.cmpr_b = 0.0; MCPWM_GEN_B, 100-i);
pwm_config.counter_mode = MCPWM_UP_COUNTER; vTaskDelay(10 / portTICK_PERIOD_MS);
pwm_config.duty_mode = MCPWM_DUTY_MODE_0; }
//Configure PWM0A & PWM0B with above settings } // end while
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); } // end main Mạch LED:

Biên dịch, nạp chương trình và quan sát độ của built-in LED
Thay đổi thời gian trễ, quan sát kết quả!
vankhanh@ctu.edu.vn 45
PushButton tại GPIO0
GPIO2
LED1
Bài tập áp dụng

LED2

GPIO16

Viết chương trình với các chức năng sau:

1) điều khiển độ sáng của LED2 cách nhấn vào SW3, mỗi lần nhấn độ sáng tăng 5%, độ sáng về
0% khi độ sáng đạt tối đa,

2) in phần trăm độ sáng hiện tại lên cửa sổ Serial monitor,

3) bình thường LED1 chớp tắt với tần số 1Hz.

vankhanh@ctu.edu.vn 46
ADC modules
❑Two 12-bit SAR (Successive
Appro. Register) ADCs
❑18 channels:
▪ ADC1: 8 channels (GPIO32 -
GPIO39)
▪ ADC2: (10 channels GPIO0, GPIO2,
GPIO4, GPIO12 - GPIO15, GOIO25 -
GPIO27)

vankhanh@ctu.edu.vn 47
Channel list
ADC1 ADC2
GPIO GPIO
Channel API definition Channel API definition
ESP32 ESP32-S2 ESP32 ESP32-S2
0 ADC2_CHANNEL_0 GPIO36 0 ADC2_CHANNEL_0 GPIO4 GPIO11
1 ADC2_CHANNEL_1 GPIO37 1 ADC2_CHANNEL_1 GPIO0 GPIO12
2 ADC2_CHANNEL_2 GPIO38 2 ADC2_CHANNEL_2 GPIO2 GPIO13
3 ADC2_CHANNEL_3 GPIO39 3 ADC2_CHANNEL_3 GPIO15 GPIO14
4 ADC2_CHANNEL_4 GPIO32 4 ADC2_CHANNEL_4 GPIO13 GPIO15
5 ADC2_CHANNEL_5 GPIO33 5 ADC2_CHANNEL_5 GPIO12 GPIO16
6 ADC2_CHANNEL_6 GPIO34 6 ADC2_CHANNEL_6 GPIO14 GPIO17
7 ADC2_CHANNEL_7 GPIO35 7 ADC2_CHANNEL_7 GPIO27 GPIO18
8 ADC2_CHANNEL_8 - GPIO9 8 ADC2_CHANNEL_8 GPIO25 GPIO19
9 ADC2_CHANNEL_9 - GPIO10 9 ADC2_CHANNEL_9 GPIO26 GPIO20

vankhanh@ctu.edu.vn 48
Channel definition typedef enum {
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO36 (ESP32), GPIO1 (ESP32-S2) */
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO37 (ESP32), GPIO2 (ESP32-S2) */
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO38 (ESP32), GPIO3 (ESP32-S2) */
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO39 (ESP32), GPIO4 (ESP32-S2) */
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO32 (ESP32), GPIO5 (ESP32-S2) */
ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO33 (ESP32), GPIO6 (ESP32-S2) */
ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO34 (ESP32), GPIO7 (ESP32-S2) */
ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO35 (ESP32), GPIO8 (ESP32-S2) */
#if CONFIG_IDF_TARGET_ESP32
ADC1_CHANNEL_MAX,
#elif CONFIG_IDF_TARGET_ESP32S2
ADC1_CHANNEL_8, /*!< ADC1 channel 8 is GPIO9 (ESP32-S2)*/
ADC1_CHANNEL_9, /*!< ADC1 channel 9 is GPIO10 (ESP32-S2) */
ADC1_CHANNEL_MAX,
#endif
} adc1_channel_t;

typedef enum {
ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO4 (ESP32), GPIO11 (ESP32-S2) */
ADC2_CHANNEL_1, /*!< ADC2 channel 1 is GPIO0 (ESP32), GPIO12 (ESP32-S2) */
ADC2_CHANNEL_2, /*!< ADC2 channel 2 is GPIO2 (ESP32), GPIO13 (ESP32-S2) */
ADC2_CHANNEL_3, /*!< ADC2 channel 3 is GPIO15 (ESP32), GPIO14 (ESP32-S2) */
ADC2_CHANNEL_4, /*!< ADC2 channel 4 is GPIO13 (ESP32), GPIO15 (ESP32-S2) */
ADC2_CHANNEL_5, /*!< ADC2 channel 5 is GPIO12 (ESP32), GPIO16 (ESP32-S2) */
ADC2_CHANNEL_6, /*!< ADC2 channel 6 is GPIO14 (ESP32), GPIO17 (ESP32-S2) */
ADC2_CHANNEL_7, /*!< ADC2 channel 7 is GPIO27 (ESP32), GPIO18 (ESP32-S2) */
ADC2_CHANNEL_8, /*!< ADC2 channel 8 is GPIO25 (ESP32), GPIO19 (ESP32-S2) */
ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 (ESP32), GPIO20 (ESP32-S2) */
ADC2_CHANNEL_MAX,
} adc2_channel_t;
vankhanh@ctu.edu.vn 49
ADC API Functions
1/ esp_err_t adc1_config_channel_atten( adc1_channel_t channel,
adc_atten_t atten);
2/ esp_err_t adc1_config_width(adc_bits_width_t width_bit)
3/ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
adc_bits_width_t bit_width,
uint32_t default_vref,
esp_adc_cal_characteristics_t *chars)
4/ int adc1_get_raw(adc1_channel_t channel)
5/ uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading,
const esp_adc_cal_characteristics_t *chars)

vankhanh@ctu.edu.vn 50
ADC API 1
API: Set the attenuation of a particular channel on ADC1 and configure its associated GPIO pin mux.
esp_err_t adc1_config_channel_atten( adc1_channel_t channel, adc_atten_t atten);
Điều kiện: #include "driver/adc.h", #include "esp_adc_cal.h"
Input: adc1_channel_t channel, adc_atten_t atten
adc1_channel_t channel ADC1 channel to configure. Tham khảo Channel list
Attenuation level:
SoC adc_atten_t enum Attenuation (dB) suggested range (mV)
ADC_ATTEN_DB_0 0 100 ~ 950
ADC_ATTEN_DB_2_5 1 100 ~ 1250
ESP32
ADC_ATTEN_DB_6 2 150 ~ 1750
adc_atten_t atten
ADC_ATTEN_DB_11 3 150 ~ 2450
ADC_ATTEN_DB_0 0 0 ~ 750
ADC_ATTEN_DB_2_5 1 0 ~ 1050
ESP32-S2
ADC_ATTEN_DB_6 2 0 ~ 1300
ADC_ATTEN_DB_11 3 0 ~ 2500

adc1_config_channel_atten(ADC_CHANNEL_0, ADC_ATTEN_DB_2_5); 51
vankhanh@ctu.edu.vn
API: Setting ADC resolution. ADC API 2
esp_err_t adc1_config_width(adc_bits_width_t width_bit)
Điều kiện: #include "driver/adc.h", #include "esp_adc_cal.h"

Input: adc_bits_width_t width_bit


Value API definition ADC resolution
0 ADC_WIDTH_BIT_9 9 – bit
adc_bits_width_t width_bit 1 ADC_WIDTH_BIT_10 10 – bit
2 ADC_WIDTH_BIT_11 11 – bit
3 ADC_WIDTH_BIT_12 12 – bit

Output: esp_err_t
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error

adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC_CHANNEL_0, ADC_ATTEN_DB_2_5);
vankhanh@ctu.edu.vn 52
API: Characterize an ADC at a particular attenuation.
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
ADC API 3
adc_atten_t atten, adc_bits_width_t bit_width,
uint32_t default_vref, esp_adc_cal_characteristics_t *chars)
Điều kiện: #include "driver/adc.h"
#include "esp_adc_cal.h"
Input: params
ADC_UNIT_1: ADC module 1
adc_unit_t adc_num
ADC_UNIT_2: ADC module 2
ADC_ATTEN_DB_0: (100 ~ 950) mV
adc_atten_t atten ADC_ATTEN_DB_2_5: (100 ~ 1250) mV
(Tham khảo API 1, giá trị trong bảng
này áp dụng cho ESP32) ADC_ATTEN_DB_6: (100 ~ 1750) mV
ADC_ATTEN_DB_11: (100 ~ 2450) mV
ADC_WIDTH_BIT_9
ADC_WIDTH_BIT_10
adc_bits_width_t bit_width
ADC_WIDTH_BIT_11
ADC_WIDTH_BIT_12
vankhanh@ctu.edu.vn 53
ADC API 3 (Cont.)
Input: params
Default ADC reference voltage in mV (Only in
uint32_t default_vref
ESP32)
Pointer to empty structure used to store ADC
esp_adc_cal_characteristics_t *chars
characteristics

Output: esp_err_t
ESP_OK Success
ESP_ERR_INVALID_ARG Parameter error

//Characterize ADC
adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11,
ADC_WIDTH_BIT_12, 1100, adc_chars);

vankhanh@ctu.edu.vn 54
API: Take an ADC1 reading from a single channel.
ADC API 4
int adc1_get_raw(adc1_channel_t channel)
Điều kiện: #include "driver/adc.h"
#include "esp_adc_cal.h"

Input: adc1_channel_t channel


adc1_channel_t channel Tham khảo Channel list

Output: int
int Giá trị (32 bit) chuyển đổi điện áp tại chân Analog của kênh channel

#define NO_OF_SAMPLES 32

//Multisampling
for (int i = 0; i < NO_OF_SAMPLES; i++) {
adc_reading += adc1_get_raw((adc1_channel_t) ADC_CHANNEL_6);
}
adc_reading /= NO_OF_SAMPLES;
vankhanh@ctu.edu.vn 55
ADC API 5
API: Convert an ADC reading to voltage in mV based on the ADC’s characteristics.
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading,
const esp_adc_cal_characteristics_t *chars)
Điều kiện: #include "driver/adc.h"
#include "esp_adc_cal.h"

Input: uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)


uint32_t adc_reading ADC reading
const esp_adc_cal_characteristics_t *chars Pointer to empty structure used to store ADC characteristics

Output: uint32_t
uint32_t Giá trị điện áp (mV) chuyển đổi từ giá trị số đã đọc được từ một kênh nào đó

uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);


printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage);

vankhanh@ctu.edu.vn 56
#include "freertos/FreeRTOS.h"
ADC Aplication: LDR, LM35 #include
#include
"freertos/task.h"
"driver/adc.h"
#include "esp_adc_cal.h"

#define DEFAULT_VREF 1100


#define NO_OF_SAMPLES 32 //Multisampling

static esp_adc_cal_characteristics_t *adc_chars;


void app_main(void) //GPIO34 if ADC1, GPIO14 if ADC2
{ static const adc_channel_t channel = ADC_CHANNEL_6;
//Configure ADC static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
adc1_config_width(width); static const adc_atten_t atten = ADC_ATTEN_DB_11;
static const adc_unit_t unit = ADC_UNIT_1;
//Characterize ADC
adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_chars);

//Continuously sample ADC1


while (1) {
uint32_t adc_reading = 0;
//Multisampling
for (int i = 0; i < NO_OF_SAMPLES; i++) {
adc_reading += adc1_get_raw((adc1_channel_t)channel);
}
adc_reading /= NO_OF_SAMPLES;
//Convert adc_reading to voltage in mV
uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}

vankhanh@ctu.edu.vn 57
Bài tập
Bài 1: Sử dụng GPIO, điều khiển chớp tắt LED, tần số chớp tắt được thết lập từ giá trị ADC.
ADC sử dụng độ phân giải 9-bit, tần số tối thiểu 0.5Hz, tối đa 50Hz.
Bài 2: Điều khiển trạng thái LED: nếu như điện áp đọc được:
+ từ 0 đến 1.5V: LED tắt,
+ từ >1.5V: LED sáng.
Bài 3. Điều khiển độ sáng LED sử dụng kết quả chuyển đổi ADC, 8 độ sáng khác nhau (mỗi
một mức LED sáng 1/8 công suất)
Bài 4: Điều khiển sáng LED sử dụng LDR.

vankhanh@ctu.edu.vn 58
Nội dung 2: MIT-App Inventor
❑ Nắm được các kỹ thuật tạo và lập trình một App Android đơn giản
❑ Hiểu và vận dụng được một số thành phần giao diện (Components) trong
phát triển ứng dụng

vankhanh@ctu.edu.vn 59
MIT-App Inventor
❑ Một công cụ phát triển Android app rất dễ sử dụng
▪ Phiên bản hiện tại: 2.0 beta
▪ Trang chủ: http://appinventor.mit.edu

❑ Hoạt động hoàn toàn trên trình duyệt Web.


▪ Hỗ trợ: Chrome, Firefox and Safari.
▪ Tham khảo yêu cầu hệ thống tại: http://appinventor.mit.edu/explore/ai2/setup.html

vankhanh@ctu.edu.vn 60
Starting App Inventor
❑ Mở trình duyệt hỗ trợ của App Inventor (ví dụ như Chrome) trên máy tính
❑ Truy cập vào địa chỉ http://ai2.appinventor.mit.edu để khởi đông App Inventor
❑ Đăng nhập sử dụng tài khoản Google.
❑ Từ giao diện ứng dụng có thể: tạo mới, lưu trữ, export và import dễ dàng các dự án
ứng dụng

vankhanh@ctu.edu.vn 61
Android Application
❑ Chọn Designer view để thiết kế giao diện ứng dụng
❑ Trong App Inventor, Android app được thiết kế dựa trên kéo thả các thành phần ứng
(components) dụng và viết mã lệnh dạng code blocks thay vì Java hay Kotlin

vankhanh@ctu.edu.vn 62
Components
❑ Có hai loại components:
▪ Visible components (có thể nhìn thấy trên màn hình thiết bị): Sử dụng để tạo UI (User interface)
cho ứng dụng,
▪ Non-visible components: Sử dụng các hàm của Android devices ở phía sau màn hình, ví dụ như
rung, cảm biến ánh sáng, gia tốc,...

❑ Trong một dự án mới, một Screen component được đặt tên Screen1 đã được thêm vào
sẵn trên UI của app.

vankhanh@ctu.edu.vn 63
Adding Component
❑ Palette > User Interface: Các UI components sẽ được liệt kê và sẵn dùng cho việc kéo
thả vào UI Screen (Viewer).
❑ Kéo Button từ Palette > User Interface vào bất kỳ một vị trí nào trên Screen1 trong
của sổ Viewer. Vị trí nút được đặt tự động trên Screen1.

vankhanh@ctu.edu.vn 64
Parent - Child Relationship
❑ Ví dụ: khi SpeakButton được đặt vào Screen1, Screen1 được gọi là container hay
parent của SpeakButton. SpeakButton được gọi là child của Screen1.
❑Không phải tất cả các loại components đều có thể là container.

vankhanh@ctu.edu.vn 65
Component List
❑ Tên mặc định của button là Button1 (1 sẽ thay đổi theo số lượng button được thêm vào).
❑ Tên mặc định của một component là component type theo sau bởi một số interger. Số
integer sẽ tăng theo số component được thêm vào ứng dụng.
❑ Bất kỳ một component, ngoại trừ Screen1, có thể được đổi tên hay xóa sử dụng các nút
chức năng Rename hay Delete trên Component list.

Hãy đổi tên Button1 thành SpeakButton.

vankhanh@ctu.edu.vn 66
Component Property
❑ Các đặt trưng của một component (ví dụ như vị trí của nó trong parent) được thay đổi
thông qua các thuộc tính (properties) của nó.
❑ Tất cả các visible và non-visible components đều sở hữu các thuộc tính riêng.
❑ Hãy click chọn SpeakButton trong Component list và sau đó đổi thuộc tính Text thành
“Speak it”.

vankhanh@ctu.edu.vn 67
Screen Properties
❑ Đọc qua tất cả các thuộc tính của Screen component để
làm quen cũng như tìm hiểu ý nghĩa của chúng.
❑ Thử thay đổi các thuộc tính của Screen1 như sau:
❑ AboutScreen thành “Main screen”.
❑ AppName thành “Hello World”.
❑ Title thành “Hello World”.
❑ AlignHorizontal thành "Center".

SpeakButton được đặt như thế nào trên Screen1?

vankhanh@ctu.edu.vn 68
Button Properties
❑ Tương tự, hãy đọc qua và tìm hiểu các thuộc tính
của button.
❑ Với nút SpeakButton, hãy thử một số thiết lập như
Width và Height để thấy nó thay đổi như thế nào
trong Viewer.
❑ Automatic sẽ tự động thiết lập thông số tương ứng
cho phù hợp.

Hiệu chỉnh lại Automatic sau khi thử nghiệm.

vankhanh@ctu.edu.vn 69
Label Component
❑ Được sử dụng để hiện thị các nội dung dạng văn bản, không thể hiệu chỉnh bởi người sử
dụng.
❑ Trong Palette > User Interface, kéo Label vào Screen1 di chuyển đến ngay bên dưới nút
SpeakButton và thả khi xuất hiện đường màu xanh như hình.
❑ Các component khi được thêm vào Screen container luôn được sắp xếp theo chiều dọc.
❑ Text property của Label1 chứa nội dung cần hiển thị.
❑ Hãy đổi nó thành “Hello\nWorld” (\n là ký tự điều khiển xuống dòng mới).

vankhanh@ctu.edu.vn 70
Label Component (tt)
❑ Trong Viewer, text hiển thị trên label vẫn trên
một dòng như trên Text property, nó sẽ hiển thị
hai dòng trên khi chạy trên thiết bị.
❑ Hãy tìm hiểu các property của the Label
component.

vankhanh@ctu.edu.vn 71
Non-visible TextToSpeech Component
❑ Trong Palette > Media, kéo và thả TextToSpeech component vào Screen1.
❑ TextToSpeech là một non-visible component, nó chỉ hiện thị ở góc dưới của Viewer.
❑ TextToSpeech sẽ thực hiện text-to-speech hay đọc ra nội dung văn bản sử dụng tiếng Anh.
❑ Chỉ hỗ trợ tiếng Anh.

vankhanh@ctu.edu.vn 72
Code Blocks
❑ Chọn chế độ Blocks trong the App Inventor để chuyển sang chế độ lập trình.
❑ Chương trình của ứng dụng sẽ thực hiện một số tác được lập trình sẵn. Trong App
Inventor, chương được lập trình dưới dạng các block.

vankhanh@ctu.edu.vn 73
Code Blocks (tt)
❑ Nếu ứng dụng đa màn hình, mỗi màn hình sẽ có mã lệnh riêng của nó và được tạo trong
Viewer tương ứng.

vankhanh@ctu.edu.vn 74
Code Blocks (tt)
❑ Có 4 loại Code Blocks cho một component

vankhanh@ctu.edu.vn 75
Event Handler
❑ Event handler sẽ thực hiện một đoạn mã lệnh được đặt trong do socket của khối khi một
sự kiện cụ thể xảy ra trong component.
❑ Event được chọn ngay sau từ khóa when của khối handler.
❑ Chọn component SpeakButton trong dự án HelloWorld, sau đó chọn handler cho sự kiện
SpeakButton.Click (hoặc kéo thả nó vào Viewer).

SpeakButton.Click xảy ra khi nút SpeakButton


trên màn hình thiết bị bị click (or chạm).

Lưu ý: chỉ khi một event handler thực thi xong mã lệnh
của nó thì event handler khác mới có thể được thực
thi.

vankhanh@ctu.edu.vn 76
Event Handler Parameter
❑ Event handler có hoặc không có giá trị đặt trước (parameters) hiển thị trong khối của nó.
Ví dụ trong hình event handler có một parameter gọi là choice.

❑ Handler parameter đã được gán một giá trị cụ thể trước khi sự kiện xảy ra.
❑ Chỉ mã lệnh trong do socket mới có thể sử dụng giá trị hoặc gán nó thành một giá trị khác
bởi getter block hay setter block.

vankhanh@ctu.edu.vn 77
Code Deletion
❑ Để xóa một block trong Viewer: kéo thả nó vào trashcan, chọn nó và nhấn Delete (tất cả
các khối kết nối đến nó cũng sẽ bị xóa).
❑ Có thể Ctrl+z để Undo các bước trước đó và có thể thực hiện nhiều lần.
❑ Một block kèm theo biểu tượng warning màu đỏ chỉ thị có lỗi xảy ra, màu vàng chỉ thị
một warning xảy ra (sau khi click vào nút “Show Warning”). Click vào biểu tượng để xem
nội dung warning hay error để gở rối chương trình!

vankhanh@ctu.edu.vn 78
Method Call
❑ Method call sẽ gọi (hay thực thi) một phương thức cụ thể của component. Method là một
đoạn code thực hiện chức năng nào đó của component.
❑ Tên method được chỉ định trên code block.
❑ Ví dụ: kéo và thả TextToSpeech1.Speak block của TextToSpeech1 vào do socket của
SpeakButton.Click.

TextToSpeech1.Speak: đọc bằng tiếng Anh nội dung kết nối vào message,
message được gọi là parameter của Speak method.
vankhanh@ctu.edu.vn 79
Property Getter
❑ Property getter được sử dụng để đọc giá trị thông số của các component.
❑ Tên thông số được chỉ định ngay sau tên component cách nhau bởi dấu chấm.
❑ Kéo và thả getter block Label1.Text, kết nối đên message socket của method call
TextToSpeech1.Speak.

vankhanh@ctu.edu.vn 80
Property Setter
❑ Property setter sử dụng để gán giá trị cho các property của component.
❑ Property name được chỉ định ngay sau tên component và cách nhau bởi dấu chấm.
❑ Kéo setter block ‘set SpeakButton.Text’ thả vào do socket của event handler và đặt nó
ngay sau method ‘call TextToSpeech1.Speak’.

vankhanh@ctu.edu.vn 81
Built-In Text Code Block
❑ Blocks > Built-in > Text liệt kê các code block thực hiện các tác vụ trên chuỗi.
❑ Kéo và thả code block “ ” vào socket của the SpeakButton.Text setter.
❑ Khối này sẽ tạo ra chuỗi “ Speak again ” và gán cho thuộc tính Text của SpeakButton.

vankhanh@ctu.edu.vn 82
Using Emulator - emulator startup steps
❑ Cài đặt và chạy chương trình aiStarter trên máy tính. Tham khảo link:
https://appinventor.mit.edu/explore/ai2/setup-emulator.html
❑ Khời động cửa sổ Command line, sẵn sàng chờ kết nối từ dự án của MIT App Inventor

vankhanh@ctu.edu.vn 83
Using Emulator - emulator startup steps (tt)
❑ Chọn Connect > Emulator trong App Inventor để kết nối với emulator.
❑ Thông điệp “Connecting …” hiện ra. Emulator sẽ khởi động dưới dạng môt chương trình
Window, khi thông điệp này tắt là có thể bắt đầu sử dụng thiết bị ảo.

vankhanh@ctu.edu.vn 84
Emulator updating steps
❑ Sau đó emulator (còn gọi là Companion App) thực hiện cập nhật phiên bản mới
❑ OK khi thông điệp xác nhận xuất hiện để bắt đầu cập nhật.
❑ Chọn ‘Got It’ để đóng của sổ tiếp theo.

vankhanh@ctu.edu.vn 85
Emulator updating steps (tt)
❑ Chọn OK và Install trên của sổ của emulator
❑ Chọn Done khi hoàn thành.

vankhanh@ctu.edu.vn 86
Running App on Emulator
❑ Đóng emulator sử dụng Connect > Reset Connection trong the App Inventor.
❑ Khởi động lại emulator đã cập nhật sử dụng Connect > Emulator.
❑ Nếu emulator khởi động thành công, ứng dụng hiện tại sẽ được mở như hình.

vankhanh@ctu.edu.vn 87
HelloWorld App
❑ Yêu cầu: click vào nút Speak it trên cửa sổ của emulator, chuỗi Hello\nWorld! sẽ được đọc
ra (Không bao gồm ký tự xuống dòng ‘\n’), Text của nút sẽ đổi thành Speak again.
❑ Tạo giao diện và viết mã lệnh trên Viewer và kiểm tra trên emulator và thiết bị thật

vankhanh@ctu.edu.vn 88
Project Sharing
❑ Export dự án cần chia sẻ thành tập tin ".aia", ví dụ HelloWorld.aia: chọn Projects »
Export để lưu trữ dự án vào máy tính.
❑ Nạp dự án: chọn Projects » Import để nạp dự án (.aia) sẵn có từ máy tính.

vankhanh@ctu.edu.vn 89
Project Sharing
❑ Chạy trên thiết bị thật và hay chia sẻ file cài đặt .apk
❑ Biên dịch tập tin cài đặt: chọn Build » App, lưu .apk vào máy tính.
❑ Chia sẻ trực tiếp .apk cho thiết bị Android để mở và cài đặt nó hoặc chọn App (provide QR
code for .apk) để tạo QR code của link tải .apk.
❑ Lưu ý: Cần cho phép thiết bị cài đặt .apk từ nguồn không xác định (chọn Settings »
Security » Unknown Sources) trước khi bắt đầu cài đặt.
Chia sẻ .apk sử
dụng QR code

Lưu .apk vào máy


tính

vankhanh@ctu.edu.vn 90
Math Code Blocks
❑ Chứa các khối tính toán phổ biến như: +, -, *, /,... , sin, cos, ....
❑ Truy cập: Blocks » Built-in » Math, các code blocks sẽ được liệt kê.
❑ Truy cập nhanh một block: click vào không gian trống bất kỳ trên Viewer, gõ tên của một
code block, một danh sách gợi ý sẽ xuất hiện. Ví dụ chọn khối hằng số, sin như hình.
Shortcut to sin block

Shortcut to constant block


vankhanh@ctu.edu.vn 91
Addition example
❑ Tạo giao diện gồm một Button và viết code block như sau

Giao diện App trên


emulator/device

Giao diện App sau


khi click vào Button

vankhanh@ctu.edu.vn 92
Evaluation Order
❑ Xét ứng dụng có code block như sau:
(1+2)*3

Giao diện App trên


emulator/device

Giao diện App sau


khi click vào Button

vankhanh@ctu.edu.vn 93
Evaluation Order
❑ Trong App Inventor, thứ tự tính toán của các toán hạng trong được phân chia theo từng
code block. Các tính toán được thực hiện tuần tự hay một code block chỉ thực hiện khi
code block khác thực hiện xong.
❑ Không có code block cho dấu ngoặc đơn ‘(’, ‘)’.

Kết quả: _______________________

vankhanh@ctu.edu.vn 94
Mutator
❑ Khi block (ví dụ khối nhân) có biểu tượng hình vuông màu xanh, nó được gọi là mutator.
❑ Đối số của block có thể được thêm hoặc bỏ bớt bằng mutator block.
❑ Ví dụ, click vào mutator icon của khối nhân, và kéo thả thêm number block bên phải và
chèn vào socket bên phải:

Lệnh sau thực hiện biểu thức: 1.111 x (1 + 2) x 3:

vankhanh@ctu.edu.vn 95
Formatting Number
❑ Trong cửa sổ Blocks chọn Built-in » Math, khối format as decimal number được sử dụng
để làm tròn số, số chữ số thập phân được chọn bởi đối số places.
❑ Ví dụ sau sẽ làm tròn số 2.34649 thành 2.35, nếu places là 0 thì kết quả sẽ là 2.

vankhanh@ctu.edu.vn 96
Notifier Component
❑ Được sử dụng để hiển thị các thông báo đến người sử dụng dưới các dạng thức như:
Dialog, Roast, Notification
❑ Truy cập: Palette » User Interface
❑ Notifier sẽ hiển thị các thông tin dưới dạng một dialog có yêu cầu hoặc không yêu cầu
người sử dụng phản hồi để đóng dialog.

vankhanh@ctu.edu.vn 97
Choice Dialog
❑ Lưu dự án UsingMath với tên khác, UsingDialog.
❑ Thay thế phương thức Notifier1.ShowMessageDialog trong mã lệnh thành phương thức
Notifier1.ShowChooseDialog như sau:

vankhanh@ctu.edu.vn 98
Choice Dialog (tt)
❑ Phương thức Notifier1.ShowChooseDialog sẽ gọi hiển thị một choice dialog. Dialog này
tương tự như dialog thông thường nhưng có ít nhất hai nút nhấn và yêu cầu người sử dụng
phải lựa chọn bằng cách click vào chúng.
❑ button1Text và button2Text được gán trực tiếp bằng một chuỗi. Nút Cancel cũng có thể
được hiển thị trên dialog.
❑ Ví dụ sau minh họa việc gán tên cho hai nút này.

vankhanh@ctu.edu.vn 99
Choice dialog event
❑ Sau khi người dùng click vào một nút trên choice dialog, sự kiện AfterChoosing của
Notifier component sẽ xảy ra.
❑ Handler của sự kiện này có một tham số là choice, chứa đoạn text của nút được ấn trên
dialog, ví dụ choice = "Correct" nếu ấn nút "Correct"

vankhanh@ctu.edu.vn 100
Boolean Value & Canceling Dialog
❑ Trong lập trình, giá trị true và false được gọi là Boolean values.
❑ Truy cập các khối chứa Boolean value: Blocks » Built-in » Logic
❑ Nhóm này chứa các code block của các logical operation, bao gồm cả các code block cho
các giá trị Boolean.

vankhanh@ctu.edu.vn 101
Boolean Value & Canceling Dialog
❑ Trong một ứng dụng, phương thức Notifier1.ShowChooseDialog gọi một dialog với nút
Cancel nếu giá trị của đối số cancelable được gán bằng true. Nút này được sử dụng để
đóng dialog mà không chọn bất cứ phản hồi nào.
❑ Gán cancelable bằng true/false và kiểm tra sự thay đổi của dialog trong ứng dụng.

vankhanh@ctu.edu.vn 102
Math App
❑ Tạo dự án mới với tên là UsingMath trong App Inventor.
❑ Tạo nút nhấn Show message như minh họa trong hình.
❑ Kéo thả Notifier component (Palette » User Interface) màn hình thiết kế Screen1.

vankhanh@ctu.edu.vn 103
Math App (tt)
❑ Kéo thả phương thức Notifier1.ShowMessageDialog vào socket của event handler
Button1.Click của nút nhấn.
❑ Kết nối text code block với nội dung “Calculation result” vào title và “OK” vào
buttonText socket.
❑ Phương thức này sẽ gọi hiển thị một message dialog với tên là “Calculation result” với
một nút nhấn OK và một thông điệp là giá trị của biểu thức ở tham số message.

Viết mã lệnh cho phương thức Click của UsingMath như sau:

Chạy và kiểm tra ứng dụng!

vankhanh@ctu.edu.vn 104
Condition structure: if-then Code
❑ Truy cập: Blocks » Built-in » Control
❑ Khối if … then được được sử dụng để thực hiện code block trong socket của nó một cách
có điều kiện
❑ Block kết nối vào if được gọi là điều kiện. Một điều kiện sẽ trả về một trong hai giá trị là
true và false, vì vậy code block tại if phải trả về Boolean value.
❑ Các code block trong then socket sẽ được thực thi nếu điều kiện là true.
Biểu thức
điều kiện
Thực hiện khi
điều kiện là true

vankhanh@ctu.edu.vn 105
Logic Code Blocks & Handling Dialog Choice
❑ Trong dự án UsingIfThen sau khi click vào button trên choice dialog, sự kiện
Notifier1.AfterChoosing sẽ xảy ra. Hãy thêm handler này vào dự án.
❑ Kéo thả khối if … then (Blocks » Built-in » Control) vào socket của event handler trên.
❑ Kéo thả khối Comparison “… = …” (Blocks » Built-in » Logic) vào if socket.

vankhanh@ctu.edu.vn 106
Logic Code Blocks & Handling Dialog Choice
❑ Viết mã lệnh như sau:

❑ Thêm TextToSpeech component vào dự án và viết mã lệnh như sau:

Nếu người sử dụng click vào


nút Correct thì từ Great sẽ được
đọc ra với TextToSpeed

vankhanh@ctu.edu.vn 107
if-then-else code
❑ Nếu điều kiện của khối if ... then là false, các lệnh trong then socket sẽ không thực thi
❑ Một else socket có thể thêm vào bằng cách sử dụng mutator để thực hiện lệnh trong
trường hợp trên

vankhanh@ctu.edu.vn 108
if-then-else code (tt)
❑ Quay lại dự án UsingIfThen, thêm một phương thức TextToSpeed.Speak vào else socket để
thêm đoạn đọc cho trường hợp điều kiện là else như sau:

Kiểm tra lại kết quả của ứng dụng!

vankhanh@ctu.edu.vn 109
Small test
❑ Đoạn mã sau thực hiện tác vụ gì?

a) Đổi Text của Button1 thành "equal"


b) Đổi Text của Button1 thành "not equal"
c) Một lỗi sẽ hiển thị
d) Không thực hiện tác vụ nào cả

vankhanh@ctu.edu.vn 110
Else-if socket
❑ Khối else if có thể thêm vào để tạo khối kiểm tra điều kiện hoàn chỉnh if...else if...else
❑ Có thể thêm nhiều hơn 1 khối else if
❑ Mỗi thời điểm chỉ có code blocks trong một socket thực hiện
❑ Viết thêm mã lệnh cho ứng dụng UsingIfThen như sau và kiểm tra lại kết quả

vankhanh@ctu.edu.vn 111
Variable
❑ Biến là một đối tượng lưu các giá trị trong bộ nhớ máy tính.
❑ Giá trị của biến có thể được đọc ( sử dụng getter code block) hay thay đổi (sử dụng setter
code block).
❑ Một biến cần phải được định nghĩa và khởi tạo giá trị để có giá trị trước khi sử dụng. Có
hai loại biến:
▪ Biến toàn cục: có thể sử dụng ở bất kỳ đâu trong mã lệnh.
▪ Biến cục bộ: CHỈ có thể sử dụng ở một phạm vi nhất định trong chương trình.

❑ Biến toàn cục được khai bào bằng khối initialize global (Blocks » Built-in » Variables)
Biến cục bộ

Khai báo biến cục bộ tên var1

vankhanh@ctu.edu.vn 112
Global variable
❑ Nhóm Variables (Blocks » Built-in » Variables) chứa các code block liên quan đến biến,
“initialize global …” là khối được sử dụng để định nghĩa biến toàn cục.
❑ Để sử dụng, nó phải được đặt bên ngoài tất cả các khối trên Viewer.
❑ Biến được định nghĩa bằng cách đặt tên (tên mặc định: name) và gán giá trị (to socket)
cho nó.

vankhanh@ctu.edu.vn 113
Global Variable Example
❑ Ví dụ sau định nghĩa một biến toàn cục tên result có giá trị khởi tạo bằng1 và gán giá trị
của nó cho thuộc tính Text của Label1:

vankhanh@ctu.edu.vn 114
While Loop
❑ Nằm trong nhóm Control (Blocks » Built-in » Control), thực hiện một vòng lập với số lần
lập không xác định.
❑ Trước tiên While sẽ kiểm tra giá trị Boolean của biểu thức trong test socket và thực hiện
mã lệnh trong do socket nếu điều kiện là true. Quá trình này lập lại sau mỗi lần thực thi
xong mã lệnh trong do socket và chỉ dừng khi biểu thức điều kiện có giá trị false.

Ví dụ sau sẽ lập lại việc gán chuỗi "Hello" cho


thuộc tính text của Label1 vì điều kiện của While
loop luôn bằng true.

vankhanh@ctu.edu.vn 115
Test
❑ Đoạn mã sau thực hiện tác vụ gì?

a) Gán cho thuộc tính Text của Label1 lần lược các chuỗi "0", "1", "5" và "14".
b) Gán cho thuộc tính Text của Label1 chuỗi "9".
c) Gán cho thuộc tính Text của Label1 chuỗi "0".
d) Gán cho thuộc tính Text của Label1 lần lược các chuỗi "1", "5" và "14".

vankhanh@ctu.edu.vn 116
Usingloop Project
❑ Tiếp tục lưu lại UsingIfThen (slide trước) thành dự án mới là UsingLoop.
❑ Ứng dụng này sẽ minh họa việc tính toán giá trị của 23.
❑ Trước tiên, định nghĩa hai biến toàn cục powerCounter = 0 và result = 1.
❑ Sau đó, thêm While loop vào do socket của phương thước Button1.Click.

Blocks » Built-in » Variables Blocks » Built-in » Control

vankhanh@ctu.edu.vn 117
Usingloop Project (tt)
❑ Kéo thả khối so sánh “… = …” (Blocks » Built-in » Math) và test socket của While loop
và thay đổi toán tử "=" thành “< ” để thành lập điều kiện nhỏ hơn.

❑ Cuối cùng, hãy hoàn thiện mã lệnh như sau:

Thay đổi mã lệnh phương thức Notifier1.ShowChooseDialog để nó hiển thị thông điệp là giá trị của biến result.
Hãy kiểm tra kết quả của ứng dụng!
vankhanh@ctu.edu.vn 118
Code Comment
❑ Chú thích (comment) có thể được thêm vào một code block để ghi chú (documenting) lại
thuật toán hay hoạt động của khối đó.
❑ Để thêm một comment, click chuột phải vào khối và chọn Add Comment để hiện thị biểu
tượng dấu chẩm hỏi màu xanh trên khối. Sau đó click vào icon đó đểm thêm comment.

vankhanh@ctu.edu.vn 119
Code Duplication
❑ Click chuột phải vào một khối và chọn lệnh Duplicate để tạo bản sao chép (copy) của trên
cùng một Screen component.

❑ Một khối có thể được kéo thả vào Backpack trên Viewer hoặc chọn lệnh Add to Backpack
khi click chuột phải.
❑ Các khối trong Backpack của thể được sử dụng cho các project khác trong cùng một phiên
làm việc của App Inventor.

vankhanh@ctu.edu.vn Backpack sẽ rỗng khi bắt phiên làm việc mới! 120
Collapsing Code Blocks
❑ Các block phức tạp có thể hiển thị gọn lại bằng lệnh Collapse Block.
❑ Click chuột phải vào khối và chọn Collapse Block.
❑To expand the sequence again, use the command Expand block.

vankhanh@ctu.edu.vn 121
Clock events
❑ Clock component (Palete » Sensors) có thể phát sinh sự kiện Timer event sau mỗi khoảng
thời gian nhất định (certain interval), được thiết lập bởi thuộc tính TimerInterval, đơn vị:
milli giây.
❑ Timer event sẽ không xảy ra khi thuộc tính TimerEnabled có giá trị false.

vankhanh@ctu.edu.vn 122
Slider Component
❑ Trong Designer view, Slider component (Palette » User Interface) cho phép chọn giá trị sử
một slider.
❑Giá trị minimum và maximum của slider được thiết lập tương ứng bởi hai thuộc tính
MinValue và MaxValue.

vankhanh@ctu.edu.vn 123
Slider example
❑ Giả sử tạo một ứng dụng sử dụng Slider component cho phép người dùng chọn giá trị nằm
giữa 50.0 và 150.0, thiết lập các thuộc tính của slider như sau:

vankhanh@ctu.edu.vn 124
TextBox Component
❑ Trong Designer view, the TextBox component (Palette » User Interface) cho phép người
dùng nhập một đoạn văn bản trên màn hình ứng dụng, nó được lưu trên thuộc tính Text.

Thuộc tính Hint chứa đoạn văn bản gợi ý cho


người dùng khi nhập dữ liệu vào TextBox
component (ví dụ như các dòng gợi ý "Email
address" nếu yêu cầu người dùng nhập email).

Hint chỉ hiển thị khi thuộc tính Text rỗng.

vankhanh@ctu.edu.vn 125
Textbox example
❑ Thực hiện ứng dụng sau: 2. Mã lệnh

1. Thiết kế giao diện

3. Chạy ứng dụng, giao diện như sau:

4. Nhập thử thông tin vào Textboxt

vankhanh@ctu.edu.vn 126
Nội dung 3: Ứng dụng điều khiển sử dụng BLE
❑ Nắm tổng quan về BLE (Bluetooth Low Energy), GATT server
❑ Hiểu và vận dụng được các Code Blocks của BluetoothLE extension
❑ Hiểu và vận dụng được BLE GATT server của ESP32
❑ Xây dụng được ứng dụng điều khiển trạng thái LED, độ sáng LED sử dụng PWM, đọc
dữ liệu từ GATT server (LDR, LM35)

vankhanh@ctu.edu.vn 127
Bluetooth history
Năm Phiên bản Tính năng chính
1999 1.0 và 1.0B - Thành lập: BLUETOOTH SIG (Special Interest Group)
Tồn tại nhiều vấn đề, khó sử dụng
2002 1.1 - Phê chuẩn: IEEE Standard 802.15.1
- Khắc phục nhiều lỗi của phiên bản 1.0
- Thêm vào các kênh không mã hóa
- Nhận được RSSI - Signal Strength Indicator, hay công suất tín hiệu
- Tốc độ: tối đa 721 kbit/s
2005 2.0 + EDR - Bit rate: 3Mbit/s,
- Maximum data transfer rate including acknowledgements: 2.1Mbit/s
2007 2.1 + EDR - Tăng cường bảo mật với Secure simple pairing (SSP)
- Một số cải tiến như: tính năng phản hồi yêu cầu mở rộng để tăng thông tin phản hồi
(extended inquiry response (EIR)) và sniff subrating (giảm tiêu thụ năng lượng)
2009 3.0 + HS - Tốc độ truyền dữ liệu lý thuyết tối đa 24 Mbit/s
- AMP (Alternative MAC/PHY), the addition of 802.11 as a high-speed transport.

EDR: Enhanced Data Rate


HS: High Speed
vankhanh@ctu.edu.vn 128
Bluetooth history (tt)
Năm Phiên bản Tính năng chính
2010 4.0 - Bluetooth Smart tích hợp các giao thức của Classic Bluetooth, Bluetooth high speed và
Bluetooth Low Energy (BLE)
- BLE: giảm năng lượng tiêu thụ một cách đáng kể và giảm giá thành
2013 4.1 Chủ yếu cập nhật phần mềm
2014 4.2 Giới thiệu các tính năng cho internet vạn vật (Internet of Things)
Cải tiến: Low Energy Secure Connection with Data Packet Length Extension, Link Layer
Privacy with Extended Scanner Filter Policies,
2016 5 - Tập trung chính vào các công nghệ IoTs mới
- Tăng khả năng của các dịch vụ không kết nối, ví dụ: khả năng định vị vị trí của các kết nối.
- Tích hợp lớp giao tiếp vật lý 2 Mbit/s cho LE
- LE Long Range, LE Advertising Extensions
2019 5.1 - Angle of Arrival (AoA) and Angle of Departure (AoD):được sử dụng cho định vị và bám
các thiết bị
- Advertising Channel Index, GATT Caching
12-2019 5.2 - LE Audio, Enhanced Attribute Protocol (EATT), LE Power Control

vankhanh@ctu.edu.vn 129
BLE protocol stack
❑ Physical (PHY) layer: chứa các mạch
điện tương tự thực hiện các tác vụ
truyền thông như điều chế (modulation),
giải điều chế (Demodulation) các tín
hiệu tương tự để truyền thông các tín
hiệu số.
❑ Link Layer: giao tiếp trực tiếp với
PHY, là lớp trung gian giữa phần cứng
và phần mềm.
❑ Đảm bảo các ràng buộc về thời gian (real-
time) để tạo chính xác các khung thời gian
của chuẩn giao tiếp

vankhanh@ctu.edu.vn 130
Roles of Link layer
❑ Advertiser: gửi các gói tin quảng bá.
❑ Scanner: quét các gói tin quảng bá.
❑ Client (Master): Khởi tạo và quản lý kết nối.
❑ Server (Slave): Chấp nhận yêu cầu kết nối và tuân thủ các khung thời gian của Client

vankhanh@ctu.edu.vn 131
Bluetooth Device Address
❑ Là định danh cơ bản của thiết bị Bluetooth, tương tự như địa chỉ MAC trên các mạch giao
tiếp internet.
❑ Độ dài 48-bit (6-byte) xác định duy nhất một thiết thiết bị.
❑ Có hai loại địa chỉ: một hoặc cả hai có thể được sử dụng trên một thiết bị cụ thể:
❑ Public device address: được ghi lúc sản xuất, phải được đăng ký với IEEE Registration Authority và
không thay đổi trong suốt thời gian tồn tại của thiết bị,
❑ Random device address: có thể được lập trình trước trên thiết bị hoặc được tạo trong thời gian hoạt động

vankhanh@ctu.edu.vn 132
Advertising and Scanning
❑ BLE có duy nhất một định dạng gói dữ liệu quảng bá và hai loại gói dữ liệu người dùng
(advertising and data packets)
❑ Advertising packets phục vụ cho hai mục đích:
❑ Quảng bá dữ liệu cho các ứng dụng mà không cần thành lập một kết nối,
❑ Tìm các client và kết nối với chúng.

❑ Mỗi advertising packet có thể chứa dữ liệu tối đa 31 byte cùng với các thông tin tiêu đề cơ
bản (bao gồm địa chỉ của thiết bị Bluetooth)
❑ Các gói dữ liệu được quảng bá (mà không cần sự xuất hiện của thiết bị quét) ở một tốc độ
cố định trong khoảng từ 20 ms đến 10.24 s
❑ Có hai loại thủ tục quét:
❑ Passive scanning: Chờ các gói advertising packets
❑ Active scanning: Phát một gói "Scan Request" sau khi nhận advertising packet
vankhanh@ctu.edu.vn 133
Advertising and Scanning (tt)
❑ Minh họa hai loại thủ tục quét

vankhanh@ctu.edu.vn 134
Advertising packet types
Được phân loại dựa trên 3 thuộc tính
❑ Khả năng kết nối (connectability):
❑ Connectable: Scanner có thể khởi tạo kết nối khi nhận được gói quảng bá
❑ Non-connectable: Scanner không thể khởi tạo kết nối (gói chỉ để quảng bá)

❑ Khả năng quét (scannability):


❑ Scannable: Có thể phát một yêu cầu quét khi nhận được gói quảng bá
❑ Non-scannable: không thể

❑ Tính trực tiếp (directability):


❑ Directed: gói dữ liệu chỉ chứa địa chỉ Bluetooth của Advertiser và target Scanner, không chứa data
❑ Undirected: gói dữ liệu không chỉ định bất kỳ một scanner nào, nó có thể chứa dữ liệu.

vankhanh@ctu.edu.vn 135
Connections
Để thành lập một kết nối:
❑ Trước tiên client sẽ quét để tìm các advertisers hiện tại có thể chấp nhận yêu cầu kết nối
❑ Khi một sever phù hợp được phát hiện, client sẽ gửi gói yêu cầu kết nối đến, server sẽ
cung cấp các phản hồi và thành lập kết nối.
❑ Một kết nối đơn giản là một chuỗi các trao đổi dữ liệu giữa client và sever

vankhanh@ctu.edu.vn 136
Connections (tt)
❑ Connection interval: khoảng thời gian giữa hai sự kiện kết nối liên tiếp, từ 7.5 ms (thông
lượng cao) đến 4 s (thông lượng thấp nhưng tiêu thụ ít năng lượng).
❑ Các gói dữ liệu là đơn vị thông tin của giao thức được sử dụng để truyền tải hai chiều dữ
liệu người dùng giữa client và server. Tải lượng dữ liệu (payload) của những gói này là
27 bytes, nhưng lượng dữ liệu người dùng thật sự chỉ 20 bytes trên một gói dữ liệu

vankhanh@ctu.edu.vn 137
Host Controller Interface (HCI)
❑ HCI là một giao thức tiêu chuẩn cho phép truyền thông giữa host và controller qua các
giao tiếp nối tiếp (controller có thể nằm trên một IC riêng được kết nối qua UART hoặc
USB)
❑ HCI là một tập hợp các lệnh và sự kiện để host và controller giao tiếp với nhau bằng định
dạng gói dữ liệu và một tập các quy luật điều khiển luồng kết nối.
❑ Công nghệ hiện bán dẫn tại đã cho phép một chíp đơn có thể tích hợp đầy đủ controller,
host, and application (được gọi là System-on-Chip hay SoC), ví dụ như ESP32

vankhanh@ctu.edu.vn 138
Logical Link Control and Adaptation Protocol (L2CAP)
Cung cấp hai chức năng chính:
❑ A protocol multiplexer: nhận nhiều bộ giao thức khác nhau từ lớp trên (the Attribute Protocol
(ATT) and the Security Manager Protocol (SMP))
❑ Chuyển chúng thành định dạng gói BLE tiêu chuẩn (và ngược lại)
Chi tiết:
❑ Thực hiện fragmentation và recombination: nhận các gói dữ liệu lớn từ lớp trên và tách chúng
thành các đoạn (chunks) vừa trong 27 byte (tải lượng gói tối đa payload), nhận nhiều gói dữ liệu đã
bị phân mãnh và kết hợp chúng lại thành một gói dữ liệu lớn và gửi đến một điểm nhận xác định ở
lớp trên của host
❑ BLE: ATT – thực hiện các trao đổi dữ liệu cơ bản và SMP – cung cấp một khung để tạo và phân
phối khóa an toàn
❑ Packet header của L2CAP có dung lượng 4 byte, có nghĩa là chiều dài tải lượng dữ liệu của lớp
này là 27 - 4 = 23 byte
vankhanh@ctu.edu.vn 139
Attribute Protocol (ATT)
❑ Một giao thức client/server không trạng thái đơn giản dựa trên các thuộc tính (attributes)
của một thiết bị
❑ Trong BLE, mỗi thiết bị có thể là client, server hay cả hai; client yêu cầu dữ liệu từ server
và server gửi dữ liệu đến các client
❑ Dữ liệu được sắp xếp trong định dạng của các thuộc tính, bao gồm:
▪ 16-bit attribute handle: định danh để truy xuất giá trị thuộc tính,
▪ UUID: chỉ định loại và bản chất của dữ liệu,
▪ một tập hợp các quyền,
▪ và cuối cùng là các giá trị của dữ liệu.

❑ Một client muốn đọc hay ghi giá trị của các attribute thì phải:
▪ Phát yêu cầu đọc hay ghi đến sever kèm với handle
▪ Sever sẽ phản hồi giá trị của thuộc tính hay một xác nhận (acknowledgement)
▪ Tác vụ đọc: phân tích cú pháp của giá trị và hiểu kiểu dữ liệu dựa trên UUID của thuộc tính
▪ Tác vụ ghi: client cung cấp dữ liệu thống nhất với loại thuộc tính được ghi 140
vankhanh@ctu.edu.vn
Generic Access Profile (GAP)
❑ Ra lệnh cho các thiết bị tương tác với nhau ở cấp thấp bên ngoài giao thức thực tế
❑ Định nghĩa lớp giao thức BLE trên cùng, chỉ định làm thế nào để các thiết bị thực thi các
thủ tục điều khiển như tìm thiết bị, kết nối, an toàn, ... và để cho phép các thiết bị khác
nhau từ các hãng (vendors) khác nhau có thể trao đổi dữ liệu qua lại.

vankhanh@ctu.edu.vn 141
Generic Attribute Profile (GATT)
❑ Thiết lập chi tiết cách trao đổi tất cả profile và user data qua kết nối BLE.
❑ Chỉ giải quyết các thủ tục truyền và định dạng các dữ liệu thực tế.
❑ Cung cấp các khung tham chiếu cho tất cả các GATT - based profiles.
❑ Sử dụng Attribute Protocol như giao thức vận chuyển để trao đổi dữ liệu giữa các thiết bị.

vankhanh@ctu.edu.vn 142
GATT Server
❑ Dữ liệu được sắp xếp phân cấp thành các phần gọi là
services, service nhóm các phần dữ liệu liên quan của
người dùng thành nhóm gọi là characteristics
❑ Nhận yêu cầu từ client và gửi các đáp ứng phản hồi
lại, mỗi thiết bị BLE được bán ra ít nhất phải bao gồm
một GATT server cơ bản.
❑ GATT client gửi các yêu cầu đến server và nhận các
phản hồi từ nó.

vankhanh@ctu.edu.vn 143
UUIDs - Universally unique identifiers
❑ Là một chuỗi số 128-bit (16 bytes) được đảm bảo (hay có xác suất cao) là duy nhất toàn
cầu
❑ Bản mô tả BLE đã thêm hai định dạng UUID rút gọn: 16-bit và 32-bit
❑ Để tạo lại mã UUID 128-bit từ phiên bản rút gọn, chèn giá trị rút gọn 16 hay 32 vào
chuỗi số sau:
xxxxxxxx-0000-1000-8000-00805F9B34FB
❑ UUID rút gọn áp dụng cho tất cả các type, service và profile
❑ Việc rút gọn không áp dụng cho các UUID không xuất phát từ Bluetooth Base UUID (hay
vendor-specific UUID)

vankhanh@ctu.edu.vn 144
Attributes
❑ Đơn vị dữ liệu nhỏ nhất được định nghĩa bởi GATT (và ATT)
❑ Chúng là những phần thông tin có thể địa chỉ hóa có thể chứa dữ liệu người dùng có liên
quan (hoặc siêu dữ liệu, metadata) về cấu trúc và nhóm các thuộc tính khác nhau chứa
trong chủ server.
❑ Các attribute luôn được đặt trên server và được truy xuất (và có khả năng được thay đổi)
bởi client
❑ Chứa các thông tin về bản thân của các thuộc tính như Handle, Type, Permissions, Value
và actual data

vankhanh@ctu.edu.vn 145
Services
❑ Các dịch vụ GATT nhóm các thuộc tính liên quan trong cùng một section của GATT server
❑ Tất cả các attribute bên trong một dịch vụ đơn là định nghĩa của service
❑ Định dạng kiểu và giá trị của attribute được quy định nghiêm ngặt trong GATT
❑ Dịch vụ chính là loại dịch vụ GATT tiêu chuẩn bao gồm chức năng liên quan và tiêu chuẩn
được hiển thị bởi server.
❑ Ngược lại dịch vụ thứ cấp chỉ bao gồm các dịch vụ chính khác và chỉ có ý nghĩa bổ trợ,
không có ý nghĩa riêng của nó

vankhanh@ctu.edu.vn 146
Characteristics
❑ Là vùng chứa các dữ liệu người dùng
❑ Luôn chứa hai thuộc tính:
❑ Characteristic declaration: Cung cấp metadata về user data
❑ Characteristic value: Chứa user data trong các trường dữ liệu của nó

❑ Characteristic value có thể theo sau bởi các bộ mô tả (descriptor), mở rộng thêm các
metadata trong khai báo characteristic.
❑ Characteristic definition bao gồm các declaration, value và tất cả các descriptor

declaration
value

Hai thuộc tính đầu tiên của một characteristic đơn


vankhanh@ctu.edu.vn 147
Characteristic declaration attribute

vankhanh@ctu.edu.vn 148
Characteristic declaration attribute
❑ Characteristic Value Handle: hai byte chứa handle của attribute
❑ Characteristic UUID:
❑ Là UUID của một characteristic cụ thể
❑ Có thể là một SIG-approved UUID hay một 128-bit UUID của một hãng cụ thể

❑ Quyền: Quy định quyền của attribute


❑ Giá trị: chứa giá trị của attribute

vankhanh@ctu.edu.vn 149
Characteristic value attribute

❑ Chứa dữ liệu người dùng mà client có thể đọc hoặc ghi


❑ Sử dụng cùng UUID với Characteristic declaration attribute
❑ Mỗi UUID cụ thể sẽ tham chiếu đến việc đọc cảm biến hay giá trị ấn của một keypad
❑ Characteristic value attribute có thể chứa bất kỳ một loại dữ liệu nào có thể định nghĩa
được bằng giá trị (hữu dụng và có thể trao đổi giữa hai thiết bị)

vankhanh@ctu.edu.vn 150
Characteristic Descriptors
❑ Cung cấp thêm thông tin cho client (thông tin bổ xung về characteristic và giá trị của nó)
❑ Luôn đặt bên trong characteristic definition và theo sau characteristic value attribute
❑ Descriptors được tạo từ một attribute đơn,
❑ Characteristic descriptor declaration, UUID luôn là descriptor type
❑ Characteristic descriptor value chứa bất cứ gì được định nghĩa bởi descriptor type

vankhanh@ctu.edu.vn 151
Control application overview

Embedded side Smartphone side

ON/OFF

PWM

ADC

GATT Server

vankhanh@ctu.edu.vn 152
Embedded side
Characterictis B
(Write)
ON/OFF

Characterictis C
PWM (Write)

Characterictis A ADC
(Read)

GATT Server
GATT Server Service table

vankhanh@ctu.edu.vn 153
Attribute table Thứ tự các attribute trong Sevice
enum
{
IDX_SVC,
IDX_CHAR_A,
IDX_CHAR_VAL_A,

IDX_CHAR_B,
IDX_CHAR_VAL_B,

IDX_CHAR_C,
IDX_CHAR_VAL_C,

KC225_IDX_NB,
};

Handle UUID Permissions Value


Service 0x0040 0x00FF READ
Characteristic A Declaration 0x0041 0xFF01 READ
Characteristic A Value 0x0042 0xFF01 READ ADC Value (2 byte)
Characteristic B Declaration 0x0043 0xFF02 READ
Characteristic B Value 0x0044 0xFF02 WRITE PWM Value (2 byte)
Characteristic C Declaration 0x0045 0xFF03 READ
Characteristic C Value 0x0046 0xFF03 WRITE LED Values (1 byte)
vankhanh@ctu.edu.vn 154
Code of Attribute table
/* Service */
/* Characteristic Value */
static const uint16_t GATTS_SERVICE_UUID_TEST = 0x00FF;
[IDX_CHAR_VAL_A] =
static const uint16_t GATTS_CHAR_UUID_TEST_A = 0xFF01;
{{ESP_GATT_RSP_BY_APP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_A,
static const uint16_t GATTS_CHAR_UUID_TEST_B = 0xFF02;
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
static const uint16_t GATTS_CHAR_UUID_TEST_C = 0xFF03;
GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE; /* Characteristic Declaration */
static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ; [IDX_CHAR_B] =
static const uint8_t char_prop_write = ESP_GATT_CHAR_PROP_BIT_WRITE; {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid,
static const uint8_t char_value[4] = {0x11, 0x22, 0x33, 0x44}; ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},

/* Characteristic Value */
[IDX_CHAR_VAL_B] =
/* Full Database Description - Used to add attributes into the database */ {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_B,
static const esp_gatts_attr_db_t gatt_db[KC225_IDX_NB] = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
{ GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},
// Service Declaration
[IDX_SVC] = /* Characteristic Declaration */
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, [IDX_CHAR_C] =
ESP_GATT_PERM_READ, {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid,
sizeof(uint16_t), sizeof(GATTS_SERVICE_UUID_TEST), (uint8_t ESP_GATT_PERM_READ,
*)&GATTS_SERVICE_UUID_TEST}}, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},

/* Characteristic Declaration */ /* Characteristic Value */


[IDX_CHAR_A] = [IDX_CHAR_VAL_C] =
{{ESP_GATT_RSP_BY_APP}, {ESP_UUID_LEN_16, (uint8_t {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_C,
*)&character_declaration_uuid, ESP_GATT_PERM_READ, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}}, GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},

};

vankhanh@ctu.edu.vn 155
Server parameters
Serial monitor debug name
#define GATTS_TABLE_TAG "KC225"
Số lượng service
#define PROFILE_NUM 1
#define PROFILE_APP_IDX 0
#define ESP_APP_ID 0x55 Tên thiết bị
#define SAMPLE_DEVICE_NAME "KC225 Server"
#define SVC_INST_ID 0

/* The max length of characteristic value. When the GATT client


performs a write or prepare write operation,
* the data length must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
*/
#define GATTS_DEMO_CHAR_VAL_LEN_MAX 500 Định nghĩa kích thước data
#define PREPARE_BUF_MAX_SIZE 1024
#define CHAR_DECLARATION_SIZE (sizeof(uint8_t))

#define ADV_CONFIG_FLAG (1 << 0)


#define SCAN_RSP_CONFIG_FLAG (1 << 1)

static uint8_t adv_config_done = 0;


Bảng chứa các handle của service
uint16_t kc225_handle_table[KC225_IDX_NB];

vankhanh@ctu.edu.vn 156
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); Cho phép controller
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
Main Entry
return;
}
ret = esp_bluedroid_init(); Khởi tạo bluedroid stack
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable(); Cho phép bluedroid stack
if (ret) {
ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_ble_gatts_register_callback(gatts_event_handler); Đăng ký các sự kiện GATT server
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gatts register error, error code = %x", ret);
return;
}
ret = esp_ble_gap_register_callback(gap_event_handler); Đăng ký các sự kiện GAP
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gap register error, error code = %x", ret);
return;
}
ret = esp_ble_gatts_app_register(ESP_APP_ID); Đăng ký Applicaiton ID
if (ret){
ESP_LOGE(GATTS_TABLE_TAG, "gatts app register error, error code = %x", ret);
return;
}
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500); Thiết lập kích thước gói tối đa
if (local_mtu_ret){
ESP_LOGE(GATTS_TABLE_TAG, "set local MTU failed, error code = %x", local_mtu_ret);
}

vankhanh@ctu.edu.vn Maximum Transmission Unit (MTU) 157


Read event: GATT Event Handler
❑ Được gọi khi có một yêu cầu đọc attribute từ client
❑ Tất cả các yêu cầu đọc đều gọi chung sự kiện này
❑ Xử lý sự kiện dựa trên handle nếu có nhiều thuộc tính được đọc từ client
case ESP_GATTS_READ_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_READ_EVT");
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_READ_EVT, handle = %d, :", kc225_handle_table[IDX_CHAR_VAL_A]);
// Read ADC value
if (kc225_handle_table[IDX_CHAR_VAL_A]==param->read.handle){

esp_gatt_rsp_t rsp;
memset(&rsp, 0, sizeof(esp_gatt_rsp_t));

int32_t adc_reading = adc1_get_raw((adc1_channel_t)channel);


uint32_t volt = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
- Đọc ADC rsp.attr_value.handle = param->read.handle;
- Đổi thành Volt rsp.attr_value.len = 2;
- Tách byte rsp.attr_value.value[0] = volt;
- Gửi phản hồi rsp.attr_value.value[1] = volt>>8;
ESP_LOGI(GATTS_TABLE_TAG, "DATA: %d",volt);
esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id,
ESP_GATT_OK, &rsp);
}
break;

vankhanh@ctu.edu.vn 158
Write event:
❑ Được gọi khi có một yêu cầu ghi attribute từ client
GATT Event Handler
❑ Tất cả các yêu cầu ghi đều gọi chung sự kiện này
❑ Xử lý sự kiện dựa trên handle nếu có nhiều thuộc tính được ghi từ client
case ESP_GATTS_WRITE_EVT:
if (!param->write.is_prep){
// the data length of gattc write must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
ESP_LOGI(GATTS_TABLE_TAG, "GATT_WRITE_EVT, handle = %d, value len = %d, value :", param->write.handle, param->write.len);
esp_log_buffer_hex(GATTS_TABLE_TAG, param->write.value, param->write.len);
//PWM
if (kc225_handle_table[IDX_CHAR_VAL_B]==param->write.handle){
int sliderValue = (param->write.value[1]<<8)+param->write.value[0];
Đọc giá trị của slider và
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_GEN_A, 100*(sliderValue/1023.0)); cập nhật độ rộng xung
}
if (kc225_handle_table[IDX_CHAR_VAL_C]==param->write.handle){
int switchValue = (param->write.value[1]<<8)+param->write.value[0];
//LED1 Đọc trạng thái các SW trên App và cập
if (switchValue & 0x01) gpio_set_level(LED1, 1); nhật trạng thái các LED, ví dụ LED1
else gpio_set_level(LED1, 0);
}
/* send response when param->write.need_rsp is true*/
if (param->write.need_rsp){
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
}
}else{
/* handle prepare write */
example_prepare_write_event_env(gatts_if, &prepare_write_env, param);
}
break;

vankhanh@ctu.edu.vn 159
Applicaiton configuration
Thêm, bớt chỉ số các attribute
enum
{ Quyền của các attribute
IDX_SVC,
IDX_CHAR_A, [IDX_CHAR_A] =
IDX_CHAR_VAL_A, {{ESP_GATT_RSP_BY_APP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},
IDX_CHAR_B,
IDX_CHAR_VAL_B,

IDX_CHAR_C,
Thêm code ứng dụng vào sự kiện:
IDX_CHAR_VAL_C, static void gatts_profile_event_handler()
{
switch (event) {
KC225_IDX_NB,
...
}; case ESP_GATTS_READ_EVT:

break;
case ESP_GATTS_WRITE_EVT:
Tên thiết bị:
break;
#define SAMPLE_DEVICE_NAME "KC225 Server" case ESP_GATTS_MTU_EVT:

break;
case ESP_GATTS_CONNECT_EVT:
UUID: break;
/* Service */ case ESP_GATTS_DISCONNECT_EVT:
static const uint16_t GATTS_SERVICE_UUID_TEST = 0x00FF; break;
static const uint16_t GATTS_CHAR_UUID_TEST_A = 0xFF01; case ESP_GATTS_CREAT_ATTR_TAB_EVT:
static const uint16_t GATTS_CHAR_UUID_TEST_B = 0xFF02;
static const uint16_t GATTS_CHAR_UUID_TEST_C = 0xFF03; break;
...
}
} 160
vankhanh@ctu.edu.vn
Smartphone side
❑ Sử dụng BluetoothLE extension của MIT để lập trình giao tiếp với GATT sever

Link cài đặt extension:


http://iot.appinventor.mit.edu/assets/resources/edu.mit.appinventor.ble-20200828.aix

Import extension: Sau khi cài đặt: Thêm vào ứng dụng:

vankhanh@ctu.edu.vn 161
BluetoothLE event handlers
Gọi khi tìm thấy một thiết bị hay server: Gọi khi nhận một chuỗi byte từ server:

Gọi khi kết nối thành công với server:


Gọi khi nhận một chuỗi số nguyên từ server:

Gọi khi hủy kết nối với server: Gọi khi nhận một chuỗi kí tự từ server:

vankhanh@ctu.edu.vn 162
Ghi chuỗi byte đến server:
BluetoothLE methods
Đọc chuỗi các byte từ server:

Quét tìm thiết bị hay server:

Ghi chuỗi số nguyên đến server:

Đọc chuỗi các số nguyen từ server:

Lấy thông tin Service và Chars của server:


Ghi một chuỗi ký tự đến server:

Đọc một chuỗi kí tự từ server:

vankhanh@ctu.edu.vn 163
BluetoothLE getter/setter

Thiết lập giá trị cho tham số

Đọc và trả về giá trị của tham số

vankhanh@ctu.edu.vn 164
Read State

case ESP_GATTS_READ_EVT:
ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_READ_EVT");
// Read ADC value
if (kc225_handle_table[IDX_CHAR_VAL_A]==param->read.handle){
...
esp_ble_gatts_send_response(gatts_if, param->read.conn_id,
param->read.trans_id, ESP_GATT_OK, &rsp);
}
break;

vankhanh@ctu.edu.vn 165
Write State

case ESP_GATTS_WRITE_EVT:
if (!param->write.is_prep){
//PWM
if (kc225_handle_table[IDX_CHAR_VAL_B]==param->write.handle){
int sliderValue = (param->write.value[1]<<8)+param->write.value[0];
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_GEN_A, 100*(sliderValue/1023.0));
}
if (kc225_handle_table[IDX_CHAR_VAL_C]==param->write.handle){
int switchValue = (param->write.value[1]<<8)+param->write.value[0];
//LED1
if (switchValue & 0x01) gpio_set_level(LED1, 1);
else gpio_set_level(LED1, 0);
}
}
break;

vankhanh@ctu.edu.vn 166
Application: ScannAndConnect
❑ Thực hành tạo ứng dụng theo tài liệu của MIT:
MIT_App_Inventor_Basic_Connection.pdf

Hủy tìm kiếm Kết nối với server

Quét tìm kiếm servers Hủy kết nối

Width của HorizontalArrangement: 100% Width của mỗi Button: 25%


vankhanh@ctu.edu.vn 167
Exercise 1: Add switches to control states of LEDs
❑ Thêm 4 Switch vào giao diện và viết codeblock đọc đọc giá trị và gửi lệnh điều khiển
trạng thái LED trên GATT server

Hủy tìm kiếm Kết nối với server

Quét tìm kiếm servers Hủy kết nối

Width của HorizontalArrangement: 100% Width của mỗi Switch: 25%


vankhanh@ctu.edu.vn
Component list 168
Exercise 2: Add slider to control brightness of LED
❑ Thêm một Slider vào giao diện và viết codeblock đọc giá trị và gửi lệnh điều khiển
độ sáng LED trên GATT server

Kết nối với server

Kết nối
Hủy tìm kiếm

Quét tìm kiếm servers

Tham số của Slider

vankhanh@ctu.edu.vn 169
Exercise 3: Read and Display ADC Value
❑ Thêm Label vào giao diện, viết codeblock đọc và hiển thị giá trị điện áp tại ngõ vào
ADC trên GATT server

Kết nối với server

Kết nối
Hủy tìm kiếm

Quét tìm kiếm servers

vankhanh@ctu.edu.vn 170
Exercise 4: Show connection state of server on built-in LED

❑ Khởi tạo GPIO2 và thêm mã lệnh C vào sự kiện phù hợp để hiển thị trạng thái kết
nối của GATT server:
▪ Connection: LED sáng
▪ Disconnetion: LED chớp tắt 5 lần và tắt

vankhanh@ctu.edu.vn 171
Nội dung 4: Ứng dụng điều khiển sử dụng Wifi
❑ Trình bày được các thông số cơ bản của các chuẩn Wifi
❑ Hiểu và vận dụng được webserver và websocket trong lập trình giao tiếp với điện thoại
di động qua wifi
❑ Hiểu và vận dụng được các App Inventor Component trong lập trình giao tiếp giữa App
Android và hệ thống nhúng

vankhanh@ctu.edu.vn 172
WLAN
❑ WLAN (Wireless Local Area Network) là một công nghệ truyền thông không dây kết
nối hai hay nhiều thiết bị sử dụng hệ thống phân phối không dây (wireless distribution
system) trong phạm vi hẹp (khoảng 30m).
❑ Phạm vi ứng dụng rộng: gia đình, trường học, các tòa nhà, phòng thí nghiệm,...
❑ Các hãng cung cấp công nghệ, thiết bị chính:
▪ Cisco (43.4%, Q1 2017),
▪ HPE (Hewlett-Packard Enterprises) (16.2%, Q1 2017)
▪ Ubiquiti (6.1%, Q1 2017)
▪ Huawei (3.7%, Q1 2017)

vankhanh@ctu.edu.vn 173
Wi-Fi / Wifi
❑ Đại diện cho công nghệ WLAN, cho phép các thiết bị điện tử nối mạng sử dụng sử
dụng các băng tần vô tuyến không được giấy phép (unlicensed) ISM.
❑ Các dãy băng tần vô tuyến ISM (Industrial, Scientific, and Medical)
▪ 2.4GHz UHF (Ultra High Frequency)
▪ 5GHz SHF (Super High Frequency)

❑ Khả năng phát Wifi


▪ SHF: truyền tốc độ cao, khoảng cách ngắn
▪ UHF: tăng khả năng phủ sóng, khả năng xuyên thấu qua các vật thể rắn tốt
▪ Công nghệ đa ăn-ten (Multiple antenna / Beamforming): được áp dụng để tăng tốc độ truyền dữ liệu
và chất lượng dịch vụ QoS – Quality of Service

vankhanh@ctu.edu.vn 174
Wifi AP (Access Point)
❑ Là một thiết bị cho phép các thiết bị Wifi (Smartphones, Smart devices, Laptop, tablets,
PCs,...) kết nối với mạng có dây (wired network)
❑ APs kết nối với một Internet Gateway/Router hoặc nó được tích hợp Gateway

Internet

 Infrastructure mode
 Ad-hoc mode
Access Point

vankhanh@ctu.edu.vn 175
Infrastructure mode
Internet
❑ AP trợ giúp các thiết bị Wifi:
▪ Giao tiếp với nhau, Router Server
▪ Giao tiếp với mạng có dây.
Switch
❑ Mạng điển hình: BSS (Basic Service Set)
▪ Một AP kết nối đến mạng internet có dây
▪ Một nhóm các thiết bị Wifi sẽ kết nối đến AP

Access Point

Wireless LAN

vankhanh@ctu.edu.vn 176
Ad-hoc mode
❑ Các thiết bị Wifi hay các trạm giao tiếp trực tiếp với nhau mà không cần qua một AP
❑ Sử dụng ở các khu vực không có mạng Infrastructure mode
❑ Còn được gọi là mạng peer-to-peer hay P2P
❑ Là một IBSS – Independent Basic Service Set

Wireless LAN

vankhanh@ctu.edu.vn 177
BSS vs ESS
❑ BSS (Basic Service Set) là một basic building block của một mạng không dây 802.11
▪ Trong Infrastructure mode, BSS được tạo thành bởi một AP (Access Point) và các trạm STAs
(Stations)
▪ AP đóng vai trò như một trạm chủ điều khiển tất cả các STAs trong BSS

❑ ESS (Extended Service Set) là một tập của hai hay nhiều BSS để tạo thành một mạng
đơn
▪ Mở rộng không gian của Wifi LAN

vankhanh@ctu.edu.vn 178
ESS, ví dụ
Internet

Router

Access
Point Access
Point

BSS
BSS
vankhanh@ctu.edu.vn 179
Wifi standards
❑ Wifi specifications dựa trên các tiêu chuẩn của IEEE 802.11
❑ Chỉ định Wifi hoạt động như thế nào và các yêu cầu của nó như
▪ Packet, MAC, channel, modulation, data rate, ...
• IEEE 802.11a tốc độ có thể đạt tới 54Mbps (5GHz)
• IEEE 802.11b tốc độ có thể đạt tới 11Mbps (2.4GHz)
• IEEE 802.11g tốc độ có thể đạt tới 54Mbps (2.4GHz)
• IEEE 802.11n tốc độ có thể đạt tới 150Mbps (2.4GHz, 5GHz)
• IEEE 802.11ad tốc độ có thể đạt tới 7Gbps (5GHz)
• IEEE 802.11ac tốc độ có thể đạt tới 866.7Mbps (60GHz)
Hỗ trợ 802.11 b/g/n

vankhanh@ctu.edu.vn 180
IEEE 802.11-1997
❑ Công bố vào tháng 6 năm 1997
❑ Đây là phiên bản gốc của Wifi Standards
❑ Hỗ trợ tốc độ dữ liệu 1Mbps hoặc 2Mbps
❑ Sử dụng công nghệ CSMA/CA 2.4GHz ISM
▪ CSMA/CA: Carrier-sense multiple access with collision avoidance
▪ ISM band: Industrial, Scientific and Medical band

vankhanh@ctu.edu.vn 181
IEEE 802.11a
❑ Công bố vào tháng 9 năm 1999, phiên bản cải tiến của phiên bản gốc 1997
❑ Hỗ trợ kỹ thuật mã hóa sửa lỗi
❑ Định nghĩa các yêu cầu cho OFDM (orthogonal frequency-division multiplexing) (Kỹ
thuật mã hóa dữ liệu trong truyền thông dữ liệu số)
❑ Việc sử dụng OFDM giúp tăng tốc độ truyền dữ liệu lên đến 54Mbps
▪ Nhiều ứng dụng giải trí đã được hỗ trợ

vankhanh@ctu.edu.vn 182
IEEE 802.11b
❑ Công bố vào tháng 9 năm 1999
❑ Phiên bản mở rộng trực tiếp của phiên bản gốc 1997
❑ Cải tiến kỹ thuật điều chế tín hiệu truyền:
▪ HR-DSS/High DSS modulation (High-Rate Direct Sequence Spread Spectrum)
▪ CK modulation: Complementary Code Keying

❑ Tốc độ dữ liệu tăng lên tối đa 11Mbps


❑ Hoạt động ở dãy tần 2.4GHz ISM band

vankhanh@ctu.edu.vn 183
IEEE 802.11e
❑ Hỗ trợ EDCA (Enhanced Distributed Channel Access)
❑ Cung cấp khả năng hỗ trợ QoS
❑ Hỗ trợ DiffSev (Differentiated Service) Priority
❑ Voice – Video – Best Effort Data – Background Data

❑ IEEE 802.11e được tích hợp vào IEEE 802.11-2007 (chuẩn tổng hợp) và được ứng
dụng vào các chuẩn sau đó như IEEE 802.11n, IEEE 802.11p, IEEE 802.11ac,...

vankhanh@ctu.edu.vn 184
IEEE 802.11n
❑ Công bố tháng 10 năm 2009
❑ Cải thiện tốc độ dữ liệu liệu bằng kỹ thuật MIMO
▪ MIMO: Multi Input and Multi Out
▪ MIMO sử dụng cùng lúc nhiều ăn-ten để truyền thông một cách đồng thời sử dụng các tần số trùng
lấp (overlap frequency)

❑ Hoạt động ở cả hai dãy tần 2.4 và 5GHz ISM band


❑ Tốc độ dữ liệu có thể lên đến 150Mbps

vankhanh@ctu.edu.vn 185
IEEE 802.11g
❑ Công bố tháng 6 năm 2003, cải tiến của IEEE 802.11b
▪ Hoạt động ở băng tần 2.4GHz như IEEE 802.11b
▪ Tương thích phần cứng với IEEE 802.11b

❑ Sử dụng kỹ thuật điều chế OFDM


❑ Tốc độ dữ liệu có thể lên đến 54Mbps

vankhanh@ctu.edu.vn 186
IEEE 802.11p
❑ Công bố tháng 7 năm 2010, hỗ trợ WAVE (Wireless Access in Vehicular Environment)
❑ Hoạt động ở dãy tần 5.9GHz
❑ Sử dụng cả hai OFDM và EDCA
❑ Tốc độ dữ liệu tối đa 54MHz
❑ Hỗ trợ truyền thông V2X:
▪ V2V: Vehicle-to-Vehicle, mỗi V có một bộ điều khiển OBU – On Board Unit
▪ V2I: Vehicle-to-Infrastructure (based station, AP), được gọi là RSU – Road Side Unit
▪ V2P: Vehicle-to-Person (Smartphone, SmatWatch,...)

vankhanh@ctu.edu.vn 187
IEEE 802.11ac
❑ Công bố tháng 12 năm 2013, cải tiến dự trên IEEE 802.11n
❑ Tập trung vào cải tiến tốc độ dữ liệu
❑ Các chức năng mới
▪ Hỗ trợ kênh băng thông rộng trên dãy tần 5GHz: băng thông 80 hoặc 160MHz (40MHz trong IEEE
802.11n)
▪ Sử dụng MU-MIMO (Multi-User MIMO)
▪ High density modulation

❑ Tốc độ truyền dữ liệu tối đa lên đến 866.7Mbps ở băng thông 160MHz

vankhanh@ctu.edu.vn 188
IEEE 802.11ad
❑ Công bố tháng 12 năm 2012 (WiGig specs)
❑ Sử dụng dãy tần 60GHz cùng với mạng Wifi truyền thống để hỗ trợ tốc độ truyền dữ
liệu lên đến 7Gbps gấp 10 lần chuẩn n
❑ Hỗ trợ truyền thông đa phương tiện không dây
▪ Wireless TV displays, Audio

vankhanh@ctu.edu.vn 189
IEEE 802.11ah
❑ Công bố tháng 12 năm 2016 để hỗ trợ công nghệ IoT
❑ Hoạt động ở dãy tần 900MHz với băng thông hẹp từ 1 đến 16MHz
❑ Tiêu thụ năng lượng thấp
▪ Chuyển tiếp để mở rộng khoảng cách phục vụ
▪ Hỗ trợ giao thức Wake/doze period

❑ Khả năng kết nối hàng ngàn thiết bị IoT sử dụng chỉ một AP
❑ Tốc độ truyền dữ liệu tối đa lên đến 337Mbps: đủ để hỗ trợ đồng thời nhiều ứng dụng
IoT với nhiều loại thiết bị

vankhanh@ctu.edu.vn 190
Web Servers
❑ Phản hồi yêu cầu từ người dùng (users)
❑ Cung cấp dịch vụ về thông tin (information) hay tập tin (files)
❑ Chấp nhận các yêu cầu dưới dạng giao thức HTTP – Hypertext Transfer Protocol
❑ Lớp ứng dụng
❑ Sử dụng giao thức request–response
❑ Trao đổi dữ liệu cho nền tảng WWW
❑ Là các tài liệu chứa các liên kết đến các tài nguyên mà người dùng có thể truy cập

❑ Các tài nguyên trên Webserver được định vị bởi địa chỉ URLs - Uniform Resource
Locators
Ví dụ http://192.168.1.9/local/html

Giao thức Địa chỉ tài nguyên


Địa chỉ của máy chứa server 191
vankhanh@ctu.edu.vn
Embedded Web Servers
❑ Chạy trên các nền tảng có tài nguyên bộ nhớ và khả năng tính toán hạn chế
❑ SMEWS – Smart and Mobile Embedded Web Server
❑ Mongoose

❑ Cung cấp các thông tin từ hệ thống nhúng: trạng thái hoạt động, cảm biến,...
❑ Nhận các yêu cầu điều khiển từ client (Apps, browsers): tắt/mở đèn, thay đổi tốc độ
động cơ,...
❑ Ví dụ URL truy cập và đọc giá trị nhiệt độ hiện tại trên webserver sử dụng Mongoose

http://Server-IP-address:Port/temp-loction

http://192.168.1.9:1234/Temp

vankhanh@ctu.edu.vn 192
Embedded Webservers, programming
❑ Dựa trên nền tảng sự kiện (event-based)
❑ Sử dụng API của nền tảng cung cấp server để nhận và phản hồi yêu cầu từ các client
❑ Sử dụng API của các ngoại vi để thu thập thông tin cho các phản hồi

❑ Ví dụ phương pháp xử lý yêu cầu đọc nhiệt độ từ client trên Mongoose


Thư viện API của Mongoose

Kiểm tra sự kiện

Chuẩn bị và phản hồi thông tin đến client

vankhanh@ctu.edu.vn 193
ESP-IDF Embedded Webserver
❑ Dựa trên nền tảng sự kiện (event-based)
❑ Xử lý sự kiện: dựa trên khung xử lý (framework) của ESP-IDF
❑ Sử dụng API của các ngoại vi để thu thập thông tin cho các phản hồi

❑ Xử lý hầu hết các yêu cầu http cơ bản: HEAD, GET, PUT và POST
❑ GET request:
❑ Lấy thông tin, được xác định trong URI – Uniform Resource Identifier của yêu cầu, ví dụ:
http://192.168.1.7:1234/ldr
❑ Phản hồi kèm theo dữ liệu
❑ Ứng dụng: đọc ADC, trạng thái phím ấn, hoặc một kết quả tính toán nào đó
❑ PUT request:
❑ Cập nhật thông tin cho một tài nguyên hiện có trên server, được xác định bởi URI của yêu cầu
❑ Dữ liệu kèm theo yêu cầu
❑ Ứng dụng: Cập nhật trạng thái GPIO (Leds), tốc độ động cơ (PWM), cung cấp dữ liệu cho một tiến trình, ...

vankhanh@ctu.edu.vn 194
APIs
❑ Nhận yêu cầu int httpd_req_recv( httpd_req_t *r, char *buf, size_t buf_len )

- n: Số byte dữ liệu nhận được - r: Thông tin về yêu cầu


- HTTPD_SOCK_ERR_TIMEOUT: time out hay ngắt - buf: con trỏ đến buffer chứa dữ liệu nhận
quãng trong lúc nhận dữ liệu - buf_len: kích thước của buffer chứa dữ liệu
- ...

❑ Phản hồi yêu cầu esp_err_t httpd_resp_send( httpd_req_t *r, const char *buf, ssize_t buf_len )

- ESP_OK : gửi phản hồi thành công - r: Thông tin về yêu cầu cần phản hồi
- ESP_ERR_HTTPD_RESP_SEND : phản hồi bị lỗi - buf: con trỏ đến buffer chứa dữ liệu phản hồi
- ... - buf_len: kích thước của buffer, có thể sử dụng
hàm strlen()

vankhanh@ctu.edu.vn 195
Sử dụng mảng: Resource declaration
static const httpd_uri_t basic_handlers[] = {
{ .uri = "/ldr",
.method = HTTP_GET,
static const httpd_uri_t echo = {
.handler = ADC_get_handler,
.uri = "/ldr",
.user_ctx = NULL,
.method = HTTP_GET,
},
.handler = ADC_get_handler,
{ .uri = "/switch",
.user_ctx = NULL
.method = HTTP_GET,
};
.handler = switch_get_handler,
.user_ctx = NULL,
}, static const httpd_uri_t leds_handler = {
{ .uri = "/hello", .uri = "/leds",
.method = HTTP_GET, .method = HTTP_PUT,
.handler = hello_get_handler, .handler = leds_put_handler,
.user_ctx = NULL, .user_ctx = NULL
}, };
{ .uri = "/leds",
.method = HTTP_PUT, URI
.handler = leds_post_handler,
.user_ctx = NULL,
}, Loại yêu cầu
{ .uri = "/led-brightness",
.method = HTTP_PUT,
.handler = led_brightness_post_handler, Hàm xử lý sự kiện
.user_ctx = NULL,
},
};
vankhanh@ctu.edu.vn 196
Handler registration
Sử dụng mảng:
static const int basic_handlers_no = sizeof(basic_handlers)/sizeof(httpd_uri_t);
static void register_basic_handlers(httpd_handle_t hd)
{
int i;
ESP_LOGI(TAG, "Registering basic handlers");
ESP_LOGI(TAG, "No of handlers = %d", basic_handlers_no);
for (i = 0; i < basic_handlers_no; i++) {
if (httpd_register_uri_handler(hd, &basic_handlers[i]) != ESP_OK) {
ESP_LOGW(TAG, "register uri failed for %d", i);
return;
}
}
ESP_LOGI(TAG, "Success");
}

Khai báo riêng lẻ:


httpd_register_uri_handler(server, &ADC_get_handler);
httpd_register_uri_handler(server, &leds_post_handler);
...

vankhanh@ctu.edu.vn 197
Handler construction
Phản hồi điện áp tại chân kết nối với LDR (GET request):

/* get voltage at LDR pin */


static esp_err_t ADC_get_handler(httpd_req_t *req)
{
//read ADC volt
char buf[5];
int32_t adc_reading = adc1_get_raw((adc1_channel_t)ADC_CHANNEL_0); Thu thập dữ liệu phản hồi
uint32_t volt = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);

// chuyen thanh chuoi phan hoi ve client


int32_t s=sprintf((char*)&buf[0],"%d",volt);
httpd_resp_set_type(req, HTTPD_TYPE_TEXT); Chuẩn bị buffer và phản hồi
httpd_resp_send(req, buf, s);
return ESP_OK;
}

vankhanh@ctu.edu.vn 198
Xử lý yêu cầu PUT cập nhật độ sáng led: Handler construction
/* post new brightness for LED */
static esp_err_t led_brightness_post_handler(httpd_req_t *req)
{
char buf[11];
int ret;

/* Read data received in the request */


ret = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (ret <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) { Nhận dữ liệu từ yêu cầu
httpd_resp_send_408(req);
}
return ESP_FAIL;
}

buf[ret] = '\0';
ESP_LOGI(TAG, "PWM duty update receive %s", buf); Hiển thị và xử lý dữ liệu
int sliderValue = atoi(&buf[0]);
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_GEN_A, 100*(sliderValue/1023.0)); Cập nhật tài nguyên
httpd_resp_send(req, "OK", strlen("OK")); Phản hồi cho client
return ESP_OK;
}

vankhanh@ctu.edu.vn 199
httpd_handle_t start_tests(void){
httpd_handle_t hd = test_httpd_start();
Starting Web Server
if (hd) {
register_basic_handlers(hd); Tạo và khởi động Web Server
}
return hd;
} Đăng ký tài nguyên dựa trên các URI
static httpd_handle_t test_httpd_start(void){
pre_start_mem = esp_get_free_heap_size();
httpd_handle_t hd;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
/* Modify this setting to match the number of test URI handlers */
config.max_uri_handlers = 5;
config.server_port = 1234; Số lượng tài nguyên và cổng phục vụ
/* This check should be a part of http_server */
config.max_open_sockets = (CONFIG_LWIP_MAX_SOCKETS - 3); Số socket phục vụ đồng thời
if (httpd_start(&hd, &config) == ESP_OK) {
ESP_LOGI(TAG, "Started HTTP server on port: '%d'", config.server_port);
ESP_LOGI(TAG, "Max URI handlers: '%d'", config.max_uri_handlers);
ESP_LOGI(TAG, "Max Open Sessions: '%d'", config.max_open_sockets);
Khởi động thành công,
ESP_LOGI(TAG, "Max Header Length: '%d'", HTTPD_MAX_REQ_HDR_LEN); hiển thông các thông số
ESP_LOGI(TAG, "Max URI Length: '%d'", HTTPD_MAX_URI_LEN); của server (gở rối)
ESP_LOGI(TAG, "Max Stack Size: '%d'", config.stack_size);
return hd;
}
return NULL;
}

vankhanh@ctu.edu.vn 200
App Inventor Application

vankhanh@ctu.edu.vn 201
PUT requests
❑ Viết code blocks cho các yêu cầu PUT

vankhanh@ctu.edu.vn 202
GET requests
❑ Viết code blocks cho các yêu cầu GET

vankhanh@ctu.edu.vn 203

You might also like