Tài liệu Arduino cho người mới bắt đầu (Phần 1)
Với tốc độ phát triển của công nghệ ngày nay thì việc truyền dữ liệu qua các chuẩn truyền I2C, UART
chưa đáp ứng được đối với các dự án cần truyền dữ liệu với tốc độ cao, để đáp ứng điều đó hãng
Motorola đã đề xuất ra chuẩn truyền SPI.
Bạn đang xem 20 trang mẫu của tài liệu "Tài liệu Arduino cho người mới bắt đầu (Phần 1)", để tải tài liệu gốc về máy hãy click vào nút Download ở trên
Tóm tắt nội dung tài liệu: Tài liệu Arduino cho người mới bắt đầu (Phần 1)
Chuẩn giao tiếp truyền nhận dữ liệu SPI Chương này chúng ta sẽ tìm hiểu về một chuẩn giao tiếp khá thông dụng trong truyền nhận dữ liệu, đó là chuẩn giao tiếp truyền nhận SPI. Điểm qua 1 số nội dung sẽ tìm hiểu ở chương này: • Giới thiệu về chuẩn SPI, lịch sử hình thành và nguyên lí hoạt động. • Một số ví dụ sử dụng SPI trong truyền, nhận dữ liệu như điều khiển LED matrix và đọc giá trị nhiệt độ, áp suất, độ cao bằng cảm biến BMP280 hiển thị giá trị lên màn hình OLED. Arduino cho người mới bắt đầu 105/188 Giao thức SPI Giới thiệu Với tốc độ phát triển của công nghệ ngày nay thì việc truyền dữ liệu qua các chuẩn truyền I2C, UART chưa đáp ứng được đối với các dự án cần truyền dữ liệu với tốc độ cao, để đáp ứng điều đó hãng Motorola đã đề xuất ra chuẩn truyền SPI. SPI là chữ viết tắt của Serial Peripheral Interface, chuẩn giao tiếp nối tiếp đồng bộ tốc độ cao do hãng Motorola đề xuất được sử dụng cho truyền thông khoảng cách ngắn, chủ yếu là trong các hệ thống nhúng. Giao diện được Motorola phát triển vào giữa những năm 1980 và đã trở thành tiêu chuẩn trong thực tế. Các ứng dụng điển hình như Secure Digital cards (các loại thẻ nhớ SD ví dụ: miniSD, microSD cards) và liquid crystal displays (màn hình tinh thể lỏng). Đôi khi SPI còn được gọi là chuẩn truyền thông "4 dây" vì nó có 4 đường giao tiếp là SCK (Serial Clock), MISO (Master Input/Slave Output), MOSI (Master Output/Slave Input) và SS(Slave Select). • SCK (Serial Clock): Là đường xung giữ nhịp cho chuẩn SPI, là chân output từ master, do chuẩn SPI là giao tiếp đồng bộ nên phải cần dùng một đường giữ nhịp. Đây là sự khác biệt giữa truyền thông đồng bộ và truyền thông không đồng bộ như chuẩn giao tiếp UART. SCK giúp chuẩn SPI có tốc độ truyền/nhận dữ liệu cao và ít xảy ra lỗi trong quá trình truyền/nhận dữ liệu. • MISO (Master Input/Slave Output): Với master thì MISO là chân input và với slave là chân output, 2 chân MISO của master và slave nối trực tiếp với nhau. • MOSI (Master Output/Slave Input): Với chip master thì MOSI là chân output và với chip slave là chân input, 2 đường MOSI của master và slave nối trực tiếp với nhau. • SS (Slave Select): Là chân chọn thiết bị slave cần giao tiếp, trên thiết bị slave sẽ có một chân slave kết nối với chân SS của master và trên thiết bị master sẽ có nhiều chân SS điều khiển thiết bị slave. Chân SS trên các chip slave sẽ ở mức cao khi không giao tiếp, nếu chip master kéo đường SS của một slave nào đó xuống mức thấp thì master sẽ giao tiếp với slave đó. Chuẩn truyền SPI sử dụng kiểu truyền thông master-slave, với một master có thể điều khiển nhiều slave thông qua việc lựa chọn các đường SS (Slave Select), muốn điều khiển slave nào thì chỉ cần chọn SS của slave đó. Các thiết bị sử dụng chuẩn truyền SPI sẽ truyền dữ liệu song công (duplex communication) là truyền và nhận dữ liệu cùng lúc, master có thể gửi dữ liệu đến slave và nhận dữ liệu từ slave cùng một thời điểm. 106/188 IoT Maker Viet Nam Hình 88. Hình ảnh cách kết nối các thiết bị trong giao thức SPI (Nguồn en.wikipedia.org) SPI, ưu và nhược điểm Ưu điểm • Chuẩn truyền thông nối tiếp SPI có tốc độ truyền dữ liệu và ít lỗi phát sinh trong quá trình truyền/nhận dữ liệu hơn các chuẩn truyền nối tiếp khác. • Hỗ trợ truyền thông song công (duplex communication) là dữ liệu có thể truyền và nhận cùng một thời điểm. • Có giao diện phần cứng khá đơn giản. • Không giới hạn tốc độ xung clock, cho phép truyền dữ liệu với tốc độ cao. • Hỗ trợ điều khiển nhiều slave. Nhược điểm: • Tốn năng lượng. • Chỉ hỗ trợ một master. • Không có giao thức kiểm tra lỗi. • SPI đòi hỏi các slave có một đường SS (slave Select) riêng biệt, vì thế nếu cần nhiều slave thì sẽ cần nhiều đường SS sẽ làm tốn chân của chip master và nhiều dây sẽ gây rối. Arduino cho người mới bắt đầu 107/188 Nguyên lý hoạt động Thiết bị master và slave mỗi thiết bị có thanh ghi dữ liệu 8 bit. Khi đường SCK của master tạo ra một xung nhịp thì một bit trong thanh ghi dữ liệu của master truyền qua slave trên đường MOSI, và ngược lại một bit dữ liệu từ slave sẽ truyền qua master trên đường MISO, do 2 dữ liệu được truyền cùng một lúc trên một nhịp xung nên quá trình truyền dữ liệu này gọi là truyền dữ liệu "song công". Hình 89. Quá trình truyền nhận dữ liệu trong giao thức SPI (Nguồn learn.sparkfun.com) 108/188 IoT Maker Viet Nam SPI, các ví dụ mẫu Hiển thị chữ trên LED matrix Yêu cầu Đây là một ví dụ cơ bản của chuẩn giao tiếp nối tiếp SPI. Vi điều khiển giao tiếp với module LED matrix để hiển thị chữ. Hình 90. Hình ảnh module LED ledmatrix LED matrix 8x8 MAX7219 dùng IC 7219 để điều LED matrix 1 cách dễ dàng và đơn giản hơn, dùng 3 dây dữ liệu để truyền dữ liệu và 2 dây nguồn. Module 8x8 LED matrix sử dụng khá đơn giản, có thể điều chỉnh độ sáng của LED ngay trên phần mềm. Linh kiện cần dùng • Board IoT Maker UnoX • Module LED matrix MAX7219 • Dây cắm breadboard male-female Kết nối IoT Maker UnoX với LED matrix Board IoT Maker UnoX sẽ là master và LED matrix sẽ là slave. • Master sẽ gửi dữ liệu ra từ chân D11 (MOSI) và slave sẽ nhận dữ liệu bằng chân DIN. • Chân D13 (SCK) của master sẽ tạo xung clock qua chân CLK của slave mỗi nhịp sẽ gửi 1bit dữ liệu qua slave. • Chân D10 (SS) của master nối với chân CS của slave khi muốn giao tiếp với slave thì chân D10 (SS) của master sẽ kéo chân CS của slave xuống mức thấp. Arduino cho người mới bắt đầu 109/188 Bảng 13. Bảng kết nối LED matrix và board IoT Maker UnoX LED matrix Board IoT Maker UnoX VCC 5V GND GND DIN D11 (MOSI ) CLK D13 (SCK) CS D10 (SS) Hình 91. Hình ảnh kết nối module LED matrix với board IoT Maker UnoX Thư viện cần dùng: Với những thư viện không có sẵn trong trình biên dịch Arduino IDE thì cần phải clone (dùng với git) hoặc Download về máy và add vào chương trình. Các thư viện cần dùng cho ứng dụng được kiệt kê bên dưới: • Thư viện "SPI.h" là thư viện đã có sẵn trong trình biên dịch Arduino IDE. • Thư viện bitBangedSPI. • Thư viện MAX7219_Dot_Matrix. Source code 110/188 IoT Maker Viet Nam #include #include #include MAX7219_Dot_Matrix display (chips, 10); // Chân D10 là chân SS của board Iotmaker Uno X const byte chips = 1; // Số chip MAX7219 được sử dụng const char message [] = "IOT MAKER VN"; // Nội dung được hiển thị unsigned long lastMoved = 0; unsigned long MOVE_INTERVAL = 40; // Thời gian chạy chữ đơn vị (ms) int messageOffset; void updateDisplay () { // Hiển thị chữ của mảng message, bắt đầu từ pixel mesageOffset display.sendSmooth (message, messageOffset); // Mỗi thời gian hiển thị một pixel từ phải qua trái if (messageOffset++ >= (int) (strlen (message) * 8)) messageOffset = -chips * 8; } void setup () { display.begin (); // Khởi tạo hiển thị } void loop () { // Nội dung được hiển thị lại sau khi chạy if (millis() - lastMoved >= MOVE_INTERVAL) { updateDisplay (); lastMoved = millis(); } } Kết quả Arduino cho người mới bắt đầu 111/188 Đọc dữ liệu từ cảm biến BMP280, hiển thị trên OLED Yêu cầu Ứng dụng này giúp chúng ta đọc dữ liệu từ cảm biến áp suất và hiển thị giá trị lên màn hình OLED. Module cảm biến áp suất BMP280 Hình 92. Hình ảnh module cảm biến áp suất BMP280 BPM280 là cảm biến nâng cấp thế hệ tiếp theo cho BMP085/BMP180/BMP183. Với chi phí thấp, độ chính xác cao. Module có chức năng đo áp suất khí quyển và nhiệt độ. Chúng ta cũng có thể sử dụng nó như một module đo độ cao (sai số ± 1m) bởi mối liên hệ giữa áp suất và độ cao. Linh kiện cần dùng • Board IoT Maker UnoX • Module cảm biến áp suất BPM280 • Màn hình OLED • Dây cắm breadboard male-female Kết nối : • Arduino sẽ là master và cảm biến BMP280 sẽ là slave, slave sẽ gửi dữ liệu qua đường SDI. • Mỗi nhịp xung clock từ chân SCK (D13) của master tạo ra sẽ ứng với 1bit dữ liệu được truyền. • Chân D10 (SS) của master nối với chân CS của slave khi muốn giao tiếp với slave thì chân D10 (SS) của master sẽ kéo chân CS của slave xuống mức thấp. 112/188 IoT Maker Viet Nam Bảng 14. Bảng đấu nối cảm biến BMP280 và board IoT Maker UnoX BMP280 IoT Maker UnoX VCC 3.3V GND GND SDI D11 (MOSI ) SCK D13 (SCK) CSE D10 (SS) SDO D12(MISO) Hình 93. Hình ảnh kết nối module cảm biến áp suất BMP280 với board IoT Maker UnoX Kết nối board IoT Maker UnoX với OLED Xem chương I2C để hiểu hơn về giao tiếp Arduino giao tiếp với OLED, chúng ta có thể cắm trực tiếp OLED vào header đã được thiết kế sẵn trên board IoT Maker UnoX hoặc kết nối theo hướng dẫn bên dưới. Bảng 15. Bảng đấu nối OLED với board IoT Maker UnoX OLED IoT Maker UnoX VCC 3.3V GND GND SDA SDA(hoặc A4) SCL SCL(hoặc A5) Arduino cho người mới bắt đầu 113/188 Hình 94. Hình ảnh kết nối OLED SSD1306 với board IoT Maker UnoX Thư viện cần dùng: • Thư viện "SPI.h" và "Wire.h" là hai thư viện có sẵn trong Arduino IDE. • Thư viện Adafruit_SSD1306.h. • Thư viện Adafruit_GFX.h. • Thư viện Adafruit_Sensor.h. • Thư viện Adafruit_BMP280.h. Source code #include #include #include #include #include #include #define BMP_SCK 13 #define BMP_MISO 12 #define BMP_MOSI 11 #define BMP_CS 10 #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); // Chọn giao tiếp SPI (BMP280 có 2 chuẩn giao tiếp SPI và I2C) Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO, BMP_SCK); void setup() { Serial.begin(9600); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Lấy địa chỉ I2C của oled display.clearDisplay(); // Lệnh xóa màn hình hiển thị display.setTextColor(WHITE); // Chọn màu chữ display.setTextSize(1); // Chọn kích thước chữ display.setCursor(15, 15); // Chọn vị trí của chữ 114/188 IoT Maker Viet Nam display.print(" IOT MAKER VN "); display.display(); delay(2000); Serial.println(F("BMP280 test")); if (!bmp.begin()) { // In ra thông báo nếu kết nối thất bại Serial.println(F("Could not find a valid BMP280 sensor, check wiring!")); while (1); } else Serial.println("BMP280 OK"); // Hiển thị "BMP280 OK" khi kết nối thành công } void loop() { display.clearDisplay(); display.setTextSize(1); display.setCursor(0, 0); display.print("Temperature:"); display.print(bmp.readTemperature()); // Lấy giá trị nhiệt độ display.print("*C"); // Hiển thị giá trị nhiệt độ trên serial monitor Serial.print("Temperature:"); Serial.print(bmp.readTemperature()); // Lấy giá trị nhiệt độ Serial.println("*C"); display.setCursor(0, 10); display.print("Pressure:"); display.print(bmp.readPressure()); // Lấy giá trị áp suất display.print("Pa"); // Hiển thị giá trị áp suất trên serial monitor Serial.print("Pressure:"); Serial.print(bmp.readPressure()); // Lấy giá trị áp suất Serial.println("Pa"); display.setCursor(0, 20); display.print("h:"); display.print(bmp.readAltitude()); // Lấy giá trị độ cao display.print("m"); // Hiển thị giá trị độ cao trên serial monitor Serial.print("h:"); Serial.print(bmp.readAltitude()); // Lấy giá trị độ cao Serial.println("m"); display.display(); delay(2000); } Kết quả Arduino cho người mới bắt đầu 115/188 Hình 95. Hình ảnh kết quả hiển thị trên OLED 116/188 IoT Maker Viet Nam Tổng kết Qua phần này, bạn đã tìm hiểu được những khái niệm quan trọng trong giao tiếp SPI, các chân giao tiếp theo chuẩn SPI là SCK, MISO, MOSI, SS. Cách chọn slave để giao tiếp của master và SPI hoạt động theo kiểu truyền song công là như thế nào. Từ đó, chúng ta có thể dễ dàng xây dựng các ứng dụng có hỗ trợ giao tiếp SPI. Arduino cho người mới bắt đầu 117/188 Chuẩn giao tiếp 1-Wire Trong chương này chúng ta sẽ cùng tìm hiểu thêm về 1 chuẩn giao tiếp truyền nhận dữ liệu nữa đó là chuẩn giao tiếp 1-Wire, các ví dụ thực hành đọc cảm biến bằng chuẩn giao tiếp 1-Wire, kết hợp chuẩn giao tiếp 1-Wire với các chuẩn giao tiếp khác như I2C hay SPI. 118/188 IoT Maker Viet Nam 1-Wire 1-Wire là gì? Chuẩn giao tiếp 1-Wire được nghiên cứu và phát triển bởi Dallas Semiconductor (Maxim). Không như các chuẩn giao tiếp đã được đề cập trước đó như I2C cần 2 dây hoặc SPI cần 4 dây để truyền nhận dữ liệu. 1-Wire chỉ cần một dây để có thể truyền và nhận dữ liệu. Chuẩn giao tiếp 1-Wire là chuẩn giao tiếp không đồng bộ và bán song công (half-duplex: tại một thời điểm, tín hiệu chỉ có thể chạy theo một hướng). Vì 1-Wire chỉ sử dụng một dây để nối nguồn và truyền dữ liệu, nên khi ở trạng thái rãnh (không có dữ liệu trên đường truyền) thì nó cần phải ở mức cao, do đó cần kết nối dây này với nguồn thông qua một điện trở. Điện trở này thường được gọi là điện trở kéo lên (pull-up resistor). Tùy theo các thiết bị mà giá trị điện trở này có thể thay đổi, cần tham khảo datasheet của thiết bị để biết rõ. 1-Wire thường sử dụng các cổng logic CMOS/TTL tương ứng với mức logic 0 thì điện áp đỉnh ở mức 0.8V và điện áp tối thiểu cho mức logic 1 là 2.2V. Các thiết bị 1-Wire có nguồn cấp trong khoảng 2.8V đến 6V. 1-Wire có hai chế độ làm việc là standard và overdrive. Khi làm việc ở chế độ standard thì tốc độ truyền dữ liệu là 15.4kbps, với chế độ overdrive là 125kbps. Chuẩn giao tiếp 1-Wire tuân theo mô hình master-slave. Trên một đường truyền dữ liệu có thể gắn nhiều thiết bị slave, nhưng chỉ có duy nhất một thiết bị là master. Mỗi một thiết bị slave sẽ có duy nhất 64-bit địa chỉ lưu trữ trong bộ nhớ ROM của mình. Nhờ thế, khi kết nối vào chung một bus dữ liệu thì thiết bị master sẽ có thể nhận biết được giữa các slave. Trong 8 byte (64 bit) này sẽ được chia ra làm 3 phần chính: • Bắt đầu là LSB (least significant bit), byte đầu tiên bao gồm 8 bit được gửi đi là mã họ thiết bị (family codes) giúp xác định đó là loại thiết bị nào. 6 byte tiếp theo lưu trữ một địa chỉ riêng của từng thiết bị với 48 bit tùy biến. Byte cuối cùng MSB (most significant bit) là byte kiểm tra tính toàn vẹn của dữ liệu - cyclic redundancy check (CRC), đây là byte giúp kiểm tra xem tín hiệu gửi đi có bị lỗi hay không. Với số lượng 2^48 bit địa chỉ được tạo ra thì vấn đề về địa chỉ không phải là vấn đề chính trong chuẩn giao tiếp này. Khi có nhiều thiết bị 1-Wire trên một mạch thì nó thường được gọi là mạng 1-Wire hoặc MicroLAN. Trong mạng này, yêu cầu chỉ có duy nhất một master và phải có ít nhất là một slave. Có thế kết nối bao nhiêu slave tùy thích, nhưng khi vượt quá con số 20 thì việc truyền nhận dữ liệu có thể sẽ xảy ra lỗi. Đường truyền giữa master và slave có thể lên tới 200 mét. Khi sử dụng dây ở khoảng cách lớn thì cần Arduino cho người mới bắt đầu 119/188 được bảo quản tốt hơn, như tránh băng qua các đường dây điện để tránh tín hiệu sẽ bị nhiễu. Khi sử dụng ở khoảng cách xa, loại dây rẻ nhất và dễ sử dụng nhất là dây CAP5 được sử dụng trong mạng LAN (dây cable internet). 1-Wire hoạt động như thế nào? Chuẩn giao tiếp 1-Wire sử dụng khái niệm time slot (khe thời gian). Một time slot là một khoảng thời gian trong đó mức logic 1 hoặc 0 sẽ được ghi hoặc đọc. Time slot có khoảng thời gian là 60µs khi hoạt động ở chế độ standard, và 8µs với chế độ overdrive. Có 3 thao tác hoạt động cơ bản của 1 Wire là Reset/Present, Read, Write. 1. Reset/Present. Master sẽ kéo tín hiệu truyền xuống mức thấp trong khoảng 480µs đến 640µs. Khoảng thời gian này được hiểu là khoảng thời gian reset. Sau khoảng thời gian này, nếu có slave sẽ gửi trả tín hiệu present. Tức là slave sẽ kéo tín ... n,[MSBFIRST, LSBFIRST], value) /* Dịch 1 byte, mỗi lần dịch 1 bit, dịch từ bit cao */ unsigned long pulseIn(pin,[HIGH, LOW]) /* Trả về (ms) của xung HIGH/LOW trên chân pin */ /* CHỨC NĂNG NGẮT */ attachInterrupt(interrupt, func, mode) /* Thiết lập chức năng ngắt ở các chân digital */ /* interrupt: số ngắt (thường là chân sử dụng chức năng ngắt) func : hàm sẽ được gọi khi ngắt xảy ra (lưu ý : hàm không có tham số đầu vào cũng như kiểu trả về) mode : gồm các chế độ LOW,CHANGE, RISING, FALLING. Ngắt 180/188 IoT Maker Viet Nam sẽ được kích hoạt khi chân ngắt ở mode tương ứng */ detachInterrupt(interrupt) /* Vô hiệu hóa ngắt interrupt */ noInterrupts() /* Vô hiệu hóa tấ cả các ngắt */ interrupts() /* Cho phép tái ngắt sau khi dùng noInterrupts() */ /************************************************* * THƯ VIỆN PHỔ BIẾN * *************************************************/ /************************************************* * Serial * *Thư viện giao tiếp với PC hoặc thông qua RX/TX* *************************************************/ begin(long speed) /* Thiết lập giao tiếp serial-UART với tốc độ speed */ end() /* Vô hiệu hóa giao tiếp serial */ int available() /* Trả về số bytes có sẵn để đọc */ int read() /* đọc dữ liệu đến từ serial (trả về byte đầu tiên của dữ liệu từ serial hoặc -1 nếu dữ liệu không có */ flush() /* Chờ quá trình truyền dữ liệu serial hoàn tất */ print(data) /* In ra serial port dữ liệu data (với bất kì kiểu dữ liệu nào được thiết lập */ println(data) /* Tương tự như print(data) nhưng sau khi in ra serial -port, con trỏ sẽ xuống dòng tiếp theo */ write(byte) /* Gửi dữ liệu value/string/array đến serial port */ SerialEvent() /* Hàm được gọi khi có dữ liệu đến từ chân RX */ /************************************************* * Servo.h * * Thư viện hỗ trợ điều khiển động cơ servo * *************************************************/ attach(pin, [min_uS, max_uS]) /* Thiết lập chân kết nối với servo và độ rộng xung pin : Chân kết nối với servo [min_uS, max_uS] : Độ rộng xung tính theo us tương ứng với góc xoay từ 0 đến 180 */ write(angle) /* Ghi dữ liệu góc xoay cho động cơ angle từ 0~180 */ writeMicroseconds(uS) /* Viết giá trị để điều khiển góc quay cho servo, giá trị từ 700 ~ 2300 */ int read() /* Đọc giá trị góc xoay (0 đến 180 độ) */ bool attached() /* Trả về true nếu biến servo đã kết nối đến pin */ detach() /* Gỡ bỏ biến servo ra khỏi chân đã kết nối */ /************************************************* * Wire.h * * Dùng trong giao tiếp I2C * *************************************************/ begin() /* Master khởi tạo thư viện Wire với giao tiếp I2C */ begin(addr) /* Slave tham gia vào kết nối i2C, addr là 7 bits địa chỉ của slave */ requestFrom(address, count, stop) /* Master yêu cầu 1 số byte từ slave: address: 7bits địa chỉ của slave. count: Số lượng byte master yêu cầu stop: Kiểu boolean, nếu true, master tín hiệu stop sau khi yêu cầu và giải phóng bus I2C, nếu false, master gửi yêu cầu restart để giữ kết nối */ beginTransmission(addr) /* Gửi tín hiệu bắt đầu, truyền dữ liệu đến slave có địa chỉ addr */ send(byte) /* Gửi dữ liệu (1 byte)đến slave */ send(char * string) /* Gửi dữ liệu (string) đến slave */ send(byte * data, size) /* Gửi dữ liệu (1 mảng ) với số byte là size */ endTransmission() /* Gửi tín hiệu kết thúc truyền dữ liệu tới slave */ int available() /* Trả về số byte availabe sau khi đọc bởi read() */ byte receive() /* truy xuất đến 1 byte đã truyền từ slave đến master hoặc truyền ở chiều ngược lại khi nhận được requestFrom. Trả về byte tiếp theo đã nhận được */ onReceive(handler) /* Hàm handler sẽ được gọi khi slave nhận dữ liệu */ onRequest(handler) /* Handler sẽ được gọi khi master yêu cầu dữ liệu */ Arduino cho người mới bắt đầu 181/188 C - Cheatsheet /* CẤU TRÚC CƠ BẢN */ Viết chú thích trên 1 dòng dùng // ex: x++ ; // tăng x 1 đơn vị /* */ Viết chú thích trên nhiều dòng. ex : /************************* * Chú thích được viết * * trên nhiều dòng * ************************/ /* CẤU TRÚC 1 CHƯƠNG TRÌNH */ #include //include thư viện chuẩn của C #include "iLib.h"// include thư viện tạo bởi người dùng int global_var; //biến được dùng trong chương trình /* Khai báo hàm bắt đầu của 1 chương trình C với kiểu trả về là integer. Đối số arg kiểu int được truyền vào hàm */ int main (int arg){ float local_var ; // Biến chỉ được dùng trong hàm main Lệnh 1 ... Lệnh n ; return 0; //chương trình thực hiện thành công và thoát } /*KIỂU DỮ LIỆU VÀ PHẠM VI */ boolean true | false char -128 - 127, 'a' '$' etc. unsigned char 0 - 255 byte 0 - 255 int -32768 - 32767 unsigned int 0 - 65535 word 0 - 65535 long -2147483648 - 2147483647 unsigned long 0 - 4294967295 float -3.4028e+38 - 3.4028e+38 double -3.4028e+38 - 3.4028e+38 void i.e., no return value /* ĐẶT TÊN BIẾN */ /* Đặt tên đúng */ int x; // Một biến int x = 1; // Biến được khai báo và khởi tạo float x, y, z; // Nhiều biến cùng kiểu dữ liệu const int x = 88; // Biễn tĩnh, không ghi được int tenBien1ok; // Đặt tên biến này đúng int ten_bien_nay_ok; /* Đặt tên sai */ int 2001_tensai; // Vì số ở đầu int ten-sai; // Dấu '-' không phải là alphanumberic int while; // Sai, vì dùng từ khóa vòng lặp while /* HẰNG SỐ VÀ KIỂU DỮ LIỆU */ 123 Số thập phân 0b0111 Số nhị phân 0173 Số Octal - base 8 0x7B Số thập lục phân base 16 123U Số nguyên không dấu 123L Số nguyên có dấu 4 bytes 123UL Số nguyên không dấu 4bytes 123.0 Số thực 1.23e6 Số thực dùng cơ số mũ ex: 1.23*10^3 = 1230 /* định nghĩa hằng số a kiểu nguyên, có giá trị là 1 */ const int a = 1; /* Định nghĩa hằng số x kiểu thực, có giá trị là 4.0 */ const float x = 4; /* Định nghĩa hằng số c kiểu integer có giá trị 49 */ const c = ‘1’; // Kí tự 1 trong mã ASCII là 49 /* Định nghĩa str là hằng số kiểu con trỏ, trỏ tới chuỗi “Cheasheet C” */ const char * str = “Cheasheet C”; /* KHAI BÁO BIẾN */ /* Khai báo biến a kiểu nguyên và không gán giá trị */ int a; /* khai báo a kiểu binary, b kiểu base8, c kiểu số nguyên, d kiểu số nguyên và không gán giá trị */ int a = 0b01111011, b = 0123, c = 1, d; /* Khai báo biến fa thuộc kiểu số thực float */ float fa = 1.0f; /* Khai báo biến da thuộc kiểu số thực double */ double da = 1.0; /* Khai báo biến con trỏ và trỏ đến 1 vùng nhớ không xác định */ char *pointer; /* Khai báo biến con trỏ và trỏ về NULL (0)*/ char *other_pointer = NULL; /* CHUỖI KÍ TỰ */ /* Chuỗi bao gồm kí tự kết thúc chuỗi \0 (null) */ char str1[8] = {'A','r','d','u','i','n','o','\0'}; /* Trình biên dịch tự động thêm kí tự \0 vào cuối chuỗi */ char str2[8] = {'A','r','d','u','i','n','o'}; /* Khai báo chuỗi ,không khai báo số phần tử và gán giá trị chuỗi */ char str3[] = "Arduino"; /* Khai báo và gán giá trị cho chuỗi */ char str4[8] = "Arduino"; /* Các hàm xử lí chuỗi thường dùng */ /* Nối các kí tự từ chuỗi source tiếp vào vị trí cuối của chuỗi dest */ strcat(dest, source) /* Tìm vị trí xuất hiện đầu tiên của kí tự c trong source, trả về con trỏ chỉ tới vị trí đó hoặc null nếu không tìm thấy c trong source */ strchr(source, c) /* Hàm trả về độ dài của chuỗi st */ strlen(st) /* copy và thay các kí tự của chuỗi soure vào dest */ strcpy(dest, source) /* chép kí tự từ đầu đến n từ chuỗi source vào dest */ strncpy(dest, source, n) 182/188 IoT Maker Viet Nam /* MẢNG */ /* Khai báo mảng 1 chiều 6 phần tử kiểu integer và gán giá trị cho mỗi phần tử */ int myPins[] = {2, 4, 8, 3, 6}; /* Khai báo mảng 1 chiều 6 phần tử kiểu integer và không gán giá trị */ int myInts[6]; myInts[0] = 42; // Gán giá trị 42 cho phần tử đầu tiên myInts[6] = 12; // LỖI ! chỉ số của mảng chỉ từ 0 đến 5 /* Lấy giá trị của phần tử thứ 3 trong mảng myInts */ int c = myInts[2]; // Có thể dùng *(myInts + 2) /* Lấy địa chỉ của phần tử thứ 3 trong mảng myInts */ int c = &myInts[2]; // Có thể dùng int c = myInts + int /* Trả về chiều dài của mảng myInts */ int length = sizeof(myInts) / sizeof(myInts[0]); /* Khai báo 2 mảng kiểu float, arr1 có 5 phần tử, arr2 có 10 phần tử */ float arr1[5], arr2[10]; /* Khai báo mảng số nguyên arr có 2 dòng, 5 cột. Tổng cộng có 10 phần tử */ int a[2][5]; /* KHỐI LỆNH VÀ CÁC LỆNH DÙNG TRONG VÒNG LẶP */ {} // bao gồm nhiều lệnh, thường được sử dụng trong h àm /* Goto : chương trình sẽ nhảy đến nhãn (nhãn phải có mặt trong câu lệnh chứa goto) */ goto nhãn; /* Continue : Chỉ dùng trong các lệnh có vòng lặp sẽ chuyển qua chu kì mới của vòng lặp trong cùng nhất */ continue; /* /* Break : Dùng với các vòng lặp thoát khỏi vòng lặp trong cùng nhất, hoặc dùng trong cấu trúc switch..case để thoát ra khỏi case tương ứng */ break; /* /* Return */ /* Dùng cho hàm không có kiểu trả về (void) */ return; /* Value có thể là hằng số, biến, biểu thức hoặc gọi đến 1 hàm khác để trả về giá trị */ return ; /* LỆNH RẺ NHÁNH */ if (x < 5) // thực thi code nếu x<5 { code } else if (x > 10)// thực thi code nếu x>10 { code } else { code } // thực thi code các trường hợp còn lại switch (var) { // thực thi case có giá trị var case 1: ... break; case 2: ... break; default: ... } /* CÁC KIỂU VÒNG LẶP */ /* While: Thực hiện code nếu x<5 */ while (x < 5) { code }; /* Do-While : Thực hiện code, so sánh, nếu x<0 tiếp tục thực hiện code */ do { code } while(x < 0); /* for : Khởi tạo và gán giá trị cho i, thực hiện code tăng i nếu i < 10 */ for (int i = 0; i < 10; i++) { code }; /* PHÉP TOÁN VÀ TOÁN TỬ THƯỜNG DÙNG /* Các toán tử thường dùng */ = toán tử bằng + toán tử cộng - toán tử trừ * toán tử nhân / toán tử chia lấy phần nguyên % toán tử chia lấy phần dư == phép so sánh bằng != phép so sánh không không bằng (khác) < phép so sánh nhỏ hơn > phép so sánh lớn hơn <= phép so sánh nhỏ hơn hoặc bằng >= phép so sánh lớn hơn hoặc bằng && phép toán logic (AND) || phép toán logic (OR) ! phép toán logic (NOT) /* Các toán tử hợp nhất */ ++ tăng 1 đơn vị -- giảm 1 đơn vị += phép toán cộng và gán giá trị ex: x = 5; x+= 1; //x = 6 -= phép toán trừ và gán giá trị ex: x = 5; x-= 1; //x = 4 *= phép toán nhân và gán giá trị ex: x = 5; x*= 3; //x = 15 /= phép toán chia lấy phần nguyên và gán giá trị ex: x = 6; x/= 2; //x = 3 &= phép toán logic AND và gán giá trị ex: x = 0b1010; x&= 0110; //x =0b0010 |= phép toán logic OR và gán giá trị ex: x = 0b1010; x&= 0110; //x =0b1110 /* Các toán tử trên bit */ & and ^ xor > dịch phảii | or ~ not /* THỰC THI VỚI CON TRỎ */ &reference: // lấy địa chỉ của biến mà con trỏ trỏ tới *dereference:// lấy giá trị của biến mà con trỏ trỏ tới /* khai báo biến con trỏ kiểu int trỏ tới địa chỉ của biến a */ int a = 5; int *pointer = &a; /* CÁC KÍ TỰ ĐIỀU KHIỂN VÀ KÍ TỰ ĐẶC BIỆT */ \n Nhảy xuống dòng kế tiếp canh về cột đầu tiên \t Canh cột tab ngang. \r Nhảy về đầu hàng, không xuống hàng. \a Tiếng kêu bip. \\ In ra dấu \ \" In ra dấu " \' In ra dấu ' %%: In ra dấu % \b ~ backspace (xóa 1 ký tự ngay trước) /* HÀM VÀ CÁC VẤN ĐỀ LIÊN QUAN */ /* Khai báo prototype của hàm max, có 2 đối số đầu vào là a và b thuộc kiểu số nguyên, kết quả trả về của hàm kiểu số nguyên */ int max(int a, int b); Arduino cho người mới bắt đầu 183/188 /* Khai báo biến c là giá trị trả về của hàm max */ int c = max(5,4); /* Khai báo prototype của hàm không có đối số và không có kiểu trả về (void) */ void none(); /* TYPEDEF- Định nghĩa kiểu dữ liệu */ /* Định nghĩa kiểu unsigned char là BYTE, khai báo các biến a, b thuộc kiểu BYTE */ typedef unsigned char BYTE; BYTE a, b; /* KIỂU LIỆT KÊ - ENUMERATION (enum) */ /* khai báo kiểu dữ liệu enum là các ngày trong tuần */ enum daysOfWeek { sunday, monday, tuesday, wednesday }; /* Tạo biến toDay thuộc daysOfWeek và gán giá trị */ daysOfWeek toDay = wednesday; /* STRUCT - KIỂU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA */ /* Khai báo struct sinhVien */ struct sinhVien{ char tenSinhVien; char MSSinhVien; int tuoiSinhVien; }; /* Truy xuất đến thành phần MSSinhVien trong struct sinhVien */ sinhVien.MSSinhVien; /* Đổi tên struct sinhVien thành 1 biến duy nhất là SINHVIEN */ typedef struct sinhVien SINHVIEN; /* Khai báo biến sinhVienA thuộc struct SINHVIEN */ SINHVIEN sinhVienA; /* CÁC LỆNH XỬ LÝ TẬP TIN (#include ) */ /* Khai báo 1 biến con trỏ là đường dẫn của 1 file */ const char *filePath = "Đường/dẫn/file/document.txt"; /* Tạo 1 biến con trỏ thuộc kiểu FILE */ FILE *file; /* Mở 1 file ở đường dẫn filePath và đọc dữ liệu */ file = fopen(filePath, "r");// Trả về NULL nếu thất bại /* Đóng 1 file đã mở, trả về 0 nếu thành công , ngược lại trả về EOF */ fclose(file); /* Viết kí tự c lên file đang mở, trả về EOF nếu ghi thất bại, trả về mã ASCII của c nếu thành công */ int fputc(int c, FILE *f); /* Viết chuỗi "hello" lên file đang mở */ int c = fputs("hello", file); /* Đọc (255-1) kí tự từ file đang mở, kết quả đọc được sẽ lưu vào mảng str, việc đọc bị dừng nếu gặp kí tự '\n' hoặc EOL */ fgets(str, 255, file); /* Thay đổi vị trí trỏ đến trong file của con trỏ internal file position indicator về lại đầu file */ int fseek(file, 0, SEEK_SET); /* Trả về kích thước của nội dung có trong file */ ftell(file); www.cheatography.com/ashlyn-black/cheat-sheets/c-reference/ 184/188 IoT Maker Viet Nam Lời kết Arduino cho người mới bắt đầu 185/188 Các thành viên tham gia đóng góp Để hoàn thiện nội dung của sách có sự đóng góp của các thành viên sau: • 1. Phạm Minh Tuấn (TuanPM) - Chủ biên • 2. Trịnh Hoàng Đức - Kĩ sư thiết kế phần cứng tại IoT Maker Việt Nam. • 3. Trần Phúc Vinh - Thực tập sinh tại IoT Maker Việt Nam - Sinh viên Đại Học Bách Khoa, chuyên ngành kĩ thuật điện, khóa học 2014. • 4. Phạm Thị Thu Hiền - Designer tại IoT Maker Việt Nam. • 5. Võ Trí Dũng - Thực tập sinh tại IoT Maker Việt Nam, sinh viên Đại Học Sài Gòn, chuyên ngành điện tử máy tính, khóa học 2014. • 6. Nguyễn Minh Phương - Thực tập sinh tại IoT Maker Việt Nam, sinh viên Đại Học Sài Gòn, chuyên ngành điện tử máy tính , khóa học 2014. • 7. Đặng Quang Trung - Thực tập sinh tại IoT Maker Việt Nam, sinh viên Đại Học Sài Gòn, chuyên ngành điện tử máy tính, khóa học 2014. • 8. Lâm Nhật Quân Kĩ sư làm việc tại IoT Maker Việt Nam. • 9. Trần Thanh Lộc - Thực tập sinh tại IoT Maker Việt Nam - Sinh viên Đại Học Bách Khoa, chuyên ngành kỹ thuật máy tính, khóa học 2016. 186/188 IoT Maker Viet Nam Lời kết Thật vui khi bạn đã đồng hành cùng chúng tôi đi đến hết cuốn sách này. Mục đích của cuốn sách là giúp những người mới bắt đầu tìm hiểu về Arduino có kiến thức cơ bản và hướng đi chính xác để nghiên cứu về lập trình vi điều khiển một cách nhanh chóng hơn. Hi vọng cuốn sách sẽ đến tay thật nhiều bạn đam mê lĩnh vực điện tử lập trình tuy không còn mới mẻ nhưng rất tiềm năng này. Chúc các bạn thành công trên con đường mà mình đã chọn. Mặc dù đã cố gắng để hoàn thành tốt nhất nội dung cho cuốn sách, tuy nhiên vẫn không tránh khỏi những thiếu sót. Các bạn có thể đóng góp ý kiến để nội dung ebook hoàn thiện hơn tại địa chỉ Github IoT Maker Viet Nam Arduino cho người mới bắt đầu 187/188 Giấy phép sử dụng tài liệu. creativecommons.org/licenses/by-nc-sa/4.0/ 188/188 IoT Maker Viet Nam
File đính kèm:
- tai_lieu_arduino_cho_nguoi_moi_bat_dau_phan_1.pdf