BTN4 V5

You might also like

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

THÍ NGHIỆM ĐO LƯỜNG VÀ ĐIỀU KHIỂN

BẰNG MÁY TÍNH

BTN #4: LẬP TRÌNH CARD USB GIAO TIẾP VỚI


MÁY TÍNH

THÁNG 11 NĂM 2023


BỘ MÔN TỰ ĐỘNG, KHOA ĐIỆN ĐIỆN TỬ - ĐẠI HỌC BÁCH KHOA TP.HCM
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

BTN #4: BÀI THÍ NGHIỆM LẬP TRÌNH CARD USB GIAO
TIẾP VỚI MÁY TÍNH
A. MỤC ĐÍCH THÍ NGHIỆM

● Biết cách cấu hình ngoại vị cho vi điều khiển STM32 sử dụng phần mềm
STM32CubeMX và phần mềm Keil-C.
● Biết cách lập trình một giao diện chương trình C# bằng phần mềm Visual Studio.
● Tìm hiểu giao tiếp giữa vi điều khiển và C# qua chuẩn USB.
B. CHUẨN BỊ THÍ NGHIỆM
● Sinh viên đọc kỹ các yêu cầu của mỗi bài thí nghiệm, xem sơ đồ mạch trước khi lên
lớp.
● Sinh viên tìm hiểu cách sử dụng phần mềm STM32CubeMX, cách cài đặt thư viện
USB kết nối giữa vi điều khiển và máy tính.
C. GIỚI THIỆU MÔ HÌNH THÍ NGHIỆM
Kit thí nghiệm cho được bố trí như Hình 1

Hình 1: Sơ đồ bố trí của kit thí nghiệm Kít thí nghiệm


- Khu vực 1 – CPU: khu vực bố trí card USB. (thêm hình cái board)
- Khu vực 2 – HMI/METER: khu vực bố trí màn hình HMI và các thiết bị hiển
thị. (khu vực này chưa dùng trong nội dung thí nghiệm này)
- Khu vực 3 – AI: khu vực bố trí tín hiệu Analog, gồm các ngõ vào Analog
AI1 và AI2; Điện áp thay đổi được VR1, và VR2.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
- Khu vực 4 – ENCODER: khu vực bố trí tín hiệu ngõ vào xung tốc độ cao.
- Khu vực 5 – DI: khu vực bố trí các nút nhấn và công tắc điều khiển.
- Khu vực 6 – DO: là khu vực bố trí các LED hiển thị ngõ ra số
- Khu vực 7 – AO: là khu vực bố trí các ngõ ra điều khiển ANALOG
- Khu vực 8 – PWM-PTO: khu vực bố trí các ngõ ra xung tốc độ cao PWM và
PTO cho phép điều khiển động cơ tốc độ, vị trí động cơ DC.
- Khu vực 9 - SENSOR: khu vực bố trí lắp đặt cảm biến
- Khu vực 10: khu vực bố trí các thiết bị cho phép kết nối mạng PLC. (khu vực này
chưa dùng trong nội dung thí nghiệm này)
- Khu vực 11: khu vực nguồn áp cung cấp 12VDC và 5VDC
- Khu vực 12: khu vực ứng dụng điều khiển và hiển thị đèn giao thông.
D. THÍ NGHIỆM
I. Bài thí nghiệm 1: Khởi tạo và cấu hình vi điều khiển sử dụng phần
mềm STM32CubeMX.

Hình 1: CPU chính sử dụng cho bài thí nghiệm


❖ Tạo project với Stm32CubeMX:
- Chọn file → New project hoặc Access to MCU Selector.
- Nhập mã vi điều khiển vào ô Commercial Part Number: STM32F373C8T6.
- Ở phần danh sách chọn đúng tên vi điều khiển và nhấn Start Project.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

Hình 2: Cửa sổ chọn dòng vi điều khiển trong STM32CubeMX


- Cài đặt chế độ Debug: System Core → SYS chọn Serial Wire cho Debug.

Hình 3: Chọn chế độ Debug


- Cài đặt chế độ cho RCC.

Hình 4: Chọn chế độ cho RCC


❖ Cài đặt chức năng USB
Bài thí nghiệm sử dụng USB làm giao tiếp chính giữa vi điều khiển và máy tính. Vì thế
sinh viên cần thiết lập chức năng giao tiếp bằng USB trên vi điều khiển. Trong mục Connectivity
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
→ USB → Tick chọn Device (FS) ở mục Mode. Tiếp theo thiết lập loại usb sử dụng. Trong mục
Middleware and Software Packs, chọn Custom Human Interface Device Class (HID) và cài đặt
các thông số như hình.

Hình 5: Cài đặt chức năng USB


Kiểm tra cấu hình xung nhịp của vi điều khiển. Chọn mục Clock Configuration. Lúc này
một thông báo về việc chương trình sẽ tự động cài đặt các thông số. Sinh viên chọn No rồi cài
đặt theo hình.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

Hình 6: Cấu hình xung nhịp vi điều khiển


❖ Cấu hình chức năng ứng với từng chân của vi điều khiển
Phần tiếp theo là cài đặt cấu hình cho các chức năng sử dụng trên vid điều khiển. Nội
dung thực hiện thí nghiệm gồm các chức năng chính là GPIO, Analog, Encoder, UART.
Dựa vào Port Mapping cung cấp ở trang cuối của tài liệu thí nghiệm, sinh viên cấu hình
các chân của vi điều khiển. Cột bên trái là thứ tự của các chức năng, cột chính giữa là kiểu cấu
hình và cột bên trái vị trí PIN tương ứng trên vi điều khiển.

Hình 7: Sơ đồ chân được kích hoạt trên vi điều khiển


- DI: chức năng đọc Input của vi điều khiển chỉ cần thực hiện chọn chân với chức
năng GPIO_Input.
- DO: chức năng Output được cài đặt ở 2 dạng chính: một là tín hiệu ON/OFF và hai
là tín hiệu xung PWM. Đối với dạng 1 chỉ cận chọn chân với chức năng
GPIO_Output. Đối với dạng 2 thì sẽ sử dụng Timer (trong mục Timers)để thực hiện
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
việc xuất xung PWM. Ví dụ như DO1 và DO2 sử dụng 2 kênh của Timer 15. Dựa
vào công thức xác định giá trị tần số ngõ ra PWM, sinh viên hãy xác định 2 giá trị
Prescaler và Counter để nhập vào.
𝐹𝑚𝑎𝑥
𝐹𝑜𝑢𝑡 =
(𝑃𝑟𝑒𝑠𝑐𝑎𝑙𝑒𝑟 + 1) ∗ (𝐶𝑜𝑢𝑛𝑡𝑒𝑟 + 1)
Gợi ý: Giá trị 𝐹𝑚𝑎𝑥 của các TIM2, TIM15, TIM16 đều là 72MHz. Sinh viên dựa vào công
thức tính tần số xuất PWM để lựa chọn giá trị Prescaler và Counter cho phù hợp điền vào bảng
với các tiêu chí:
- Giá trị tần số ban đầu là 1kHz.
- Giá trị Prescaler và Counter không được vượt quá 16bits.
- Độ phân giải cho PWM mặc định là 1/1000.
- Báo cáo kết quả với GVHD
Bảng 1: Thông số cài đặt cho các timer chức năng xuất xung PWM
Prescaler Counter
TIM2
TIM15
TIM16

Hình 8: Thông số cấu hình TIM15


Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

Hình 9: Thông số cấu hình TIM16

Hình 10: Thông số cấu hình TIM2


- ADC: Sinh viên cài đặt các thông số cho ADC (trong mục Analog) theo hình bên
dưới. Lưu ý cấu hình chính xác thông số cũng như chức năng DMA của ADC.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

Hình 11: Thông số cấu hình ADC.


- DAC: Sinh viện chọn chế độ ngắt cho DAC, chế độ này sẽ liên kết với Timer 6 của
vi điều khiển nên cần cấu hình thêm Timer 6. (Dựa vào cách tính tần số PWM ở
trên sinh viên hãy xác định 2 thông số Prescaler và Counter Period của Timer 6 để
đạt được thời gian ngắt cho DAC là 50ms). Ngoài ra, Timer 6 cũng sẽ đóng vai trò
như một ngắt để đồng bộ hóa thời gian gửi dữ liệu giữa vi điều khiển và máy tính,
giá trị này cũng sẽ có thể thay đổi được nên sinh viên cài đặt giá trị phù hợp như đã
thực hiện ở phần PWM.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

Hình 12: Cấu hình DAC

Hình 13: Thông số cấu hình TIM6


- Encoder: cài đặt Timer 19 với chức năng Combined Channels là Encoder Mode.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

Hình 14: Thông số cấu hình Encoder


- USART: Sinh viên cấu hình cho chức năng USART trong Connectivity theo như
hình bên dưới.

Hình 15: Thông số cấu hình USART 2


Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

❖ Tạo file lập trình trên phần mềm Keil C


- Chọn mục Project Manager
- Chọn Toolchain / IDE là MDK-ARM với Min Version là V5.37.
- Sinh viên tự do đặt tên file ở mục Project Name và chọn nơi lưu trữ thư mục bằng
cách nhấn vào Browse ở phần Project Location. Ở phần Application Structure sinh
viên chọn Basic và không chọn vào ô Do not generate the main(). Chỉnh thông số
Minimum Stack Size = 0x1000.
- Chuyển sang mục Code Generator, sinh chọn tick chọn thêm vào ô đầu tiên ở phần
Generate files. Cuối cùng sinh viên nhấn Generate Code ở góc trên để tiến hành
tạo thư mục lập trình. Khi hộp thoại hiện lên sinh viên có thể chọn Open Project để
tự động mở Keil C.

Hình 16: Khởi tạo lập trình


II. Bài thí nghiệm 2: Lập trình vi điều khiển sử dụng Keil – C
Lưu ý: Để tránh việc mất phần lập trình khi sinh viên cần cấu hình lại cho vi điều khiển
khi dùng CubeMX, sinh viên cần gõ lệnh vào vùng giữa phần “USER CODE BEGIN” và “USER
CODE END”.
❖ Khai báo
Sinh viên mở file file main.c trong mục Application/User include file
“usbd_custom_hid_if.h” vào, tiếp theo khai báo TypeDef trong phần USER CODE BEGIN PTD
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
“extern USBD_HandleTypeDef hUsbDeviceFS;”.
Sinh viên khai báo một số biến toàn cục tĩnh cần thiết:
static uint16_t ADC_Value[2];
static volatile uint8_t ADC_done = 0;
static uint8_t usb_rx_buffer[64];
static uint8_t usb_tx_buffer[13];
static volatile uint8_t usb_tx_flag = 0;
static volatile uint8_t usb_rx_flag = 0;

Sinh viên khai báo prototype các hàm ở phần USER CODE BEGIN PFP:
void USB_RX_Interrupt(void);
void Sample_Timer_Interrupt(void);
/* DI Function */
uint8_t DI_Read_All(void);
/* DO Function */
void DO_Init(void);
void DO_Write(int n, uint8_t DO_duty);
void DO_Write_All(uint8_t *DO_duty);
void DO_pwm_set_frequency(uint32_t *frequency);//KHz
/* AI Function */
void AI_Read_All(int *AI_value);
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc);
/* AO Function */
void AO_Init(void);
void AO_Write(int n, float AO_value);
void AO_Write_All(float *AO_value);
/* Counter Function */
void Counter_Init(void);
uint32_t Counter_Read(void);
void Counter_Reset(void);
/* Sample Timer Function */
void Sample_Timer_Init(void);
void Sample_Timer_Set_Period(uint32_t Ts_ms);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim);

Viết hàm USB_RX_Interrupt ở phần BEGIN 0:


void USB_RX_Interrupt(void)
{
int i;
USBD_CUSTOM_HID_HandleTypeDef
*myusb=(USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData;
for (i=0;i<myusb->Report_buf[0];i++)
usb_rx_buffer[i]=myusb->Report_buf[i+1];
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
usb_rx_flag = 1;
}

Viết tiếp hàm Sample_Timer_Interrupt:


void Sample_Timer_Interrupt(void)
{
usb_tx_flag =1;
}

❖ Lập trình USB


Sinh viên tiến hành lập trình report descriptor trong file “usbd_custom_hid_if.c”. Sinh
viên nhập khai báo “extern void USB_RX_Interrupt(void);”. Tiếp theo sinh viên tìm đến dòng
“__ALIGN_BEGIN static uint8_t
CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE]
__ALIGN_END =” và ghi đè dòng lệnh sau vào bên trong {}:
/* USER CODE BEGIN 0 */
0x06, 0x00, 0xFF, // Usage Page = 0xFF00 (Vendor Defined Page 1)
0x09, 0x01, // Usage (Vendor Usage 1)
0xA1, 0x01, // Collection (Application)
// Input report
0x19, 0x01, // Usage Minimum
0x29, 0x40, // Usage Maximum
0x15, 0x00, // Logical Minimum (data bytes in the report may have
//minimum value = 0x00)
0x26, 0xFF, 0x00, // Logical Maximum (data bytes in the report may have
//maximum value = 0x00FF = unsigned 255)
0x75, 0x08, // Report Size: 8-bit field size
0x95, CUSTOM_HID_EPIN_SIZE, // Report Count
0x81, 0x02, // Input (Data, Array, Abs)
// Output report
0x19, 0x01, // Usage Minimum
0x29, 0x40, // Usage Maximum
0x75, 0x08, // Report Size: 8-bit field size
0x95, CUSTOM_HID_EPOUT_SIZE, // Report Count
0x91, 0x02, // Output (Data, Array, Abs)
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */

Tiếp đến sinh viên tìm đến hàm “static int8_t CUSTOM_HID_OutEvent_FS” ở gần cuối
và gọi hàm “USB_RX_Interrupt” trước return.
❖ Lập trình các hàm chức năng
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
Sinh viên lập trình tiếp ngay trong phần BEGIN 0 hoặc có thể kéo xuống dưới cùng file
main.c lập trình bên trong BEGIN 4.
● Nhóm hàm đọc tín hiệu (DI Function)
Sinh viên thực hiện viết bổ sung hoàn thiện (dựa trên ví dụ mẫu cho trước) hàm
“DI_Read_All” để đọc toàn bộ 8 chân tín hiệu Input. Chú ý, giá trị trả về của hàm này là một
biến duy nhất với kiểu dữ liệu số nguyên không dấu 8bit.
/* DI Function */
uint8_t DI_Read_All(void)
{
// Use one variable “DI_tmp” for all 8 DIs.
uint8_t DI_tmp = 0;

// Example for reading the value of DI1


DI_tmp = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_8);

// Follow the example, students complete the function to read all the values
of 8 DIs.

return DI_tmp;
}

● Nhóm hàm xuất tín hiệu (DO Function)


Hàm “DO_Init” là hàm cho trước, sinh viên sẽ thực hiện viết bổ sung hoàn chỉnh (dựa
trên ví dụ mẫu cho trước) hàm “DO_Write_All” để có thể xuất tín hiệu tương ứng với từng
chân đã chọn; Chú ý thứ tự phải chính xác với Port Mapping.
Hàm “DO_pwm_set_frequency” dùng để thay đổi tần số tín hiệu PWM khi nhận được
lệnh từ máy tính, dựa vào cách xác định giá trị cho hai thanh ghi Prescaler và Counter của Timer
ở trên, sinh viên hãy lập trình cách tính giá trị cần thiết để nhập vào thanh ghi “ARR” khi có
giá trị đầu vào từ biến con trỏ “frequency” là một mảng 3 phần tử với giá trị là tần số băm xung
PWM đơn vị là kHz nhận được từ máy tính để cài đặt cho 3 Timer 2 15 16 (giá trị này có giới
hạn từ 1 -> 255).
/* DO Function */
void DO_Init(void)
{
uint8_t DO_val[8]={0,0,0,0,0,0,0,0};
uint32_t frequency[3]={2,2,2};//2 KHz
DO_pwm_set_frequency(frequency);
DO_Write_All(DO_val);
HAL_TIM_PWM_Start(&htim15,TIM_CHANNEL_1);
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
HAL_TIM_PWM_Start(&htim15,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_4);
}

void DO_Write_All(uint8_t *DO_duty)


{
// DO_duty is an array with 8 elements
// 5 DO is PWM signal
// DO_Duty PWM between 0 -> 100%
uint32_t DO_pwm_on_time[5] = {0,0,0,0,0};
int i;
for (i=0;i<8;i++)
if (DO_duty[i] > 100) DO_duty[i] = 100;

// Example for DO signal with PWM type


/* DO1 */
DO_pwm_on_time[0] = DO_duty[0]*((TIM15->ARR)+1)/100;
TIM15->CCR1=DO_pwm_on_time[0];

// Example for DO signal with ON/OFF type


/* DO3 */
if(DO_duty[2] == 0)
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_8,GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_8,GPIO_PIN_SET);

// Follow the examples, students complete the function to write all the values
of 8 DOs.

}
void DO_pwm_set_frequency(uint32_t *frequency)//KHz
{
// Frequency is an array with 3 elements
// Example for frequency changing for DO signal with PWM type
//if (frequency[0]) TIM15->ARR = …………;

// Follow the instruction, students complete the function for the remaining 2
frequencies
}

● Nhóm hàm đọc tín hiệu Analog (AI Function)


Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
Cho trước hàm “HAL_ADC_ConvCpltCallback” có ý nghĩa sẽ được gọi sau khi ADC
của vi điều khiển đọc xong nếu có hàm kích hoạt đọc được gọi. Sinh viên thực hiện bổ sung hoàn
chỉnh hàm “AI_Read_All” để đọc 2 tín hiệu Analog. Gợi ý, sử dụng biến “ADC_done” báo hiệu
đã hoàn tất việc đọc ADC và 2 hàm kích hoạt đọc và ngừng đọc ADC. Giá trị đọc về được lưu
trong biến ADC_Value dưới dạng mảng, sinh viên sẽ gán giá trị đó vào biến con trỏ”AI_value”
để trả về giá trị đọc được này.
Hàm kích hoạt :“HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC_Value,2);”
Hàm ngừng đọc: “HAL_ADC_Stop_DMA(&hadc1);”
/* AI Function */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if (hadc->Instance == ADC1) ADC_done = 1;
}
void AI_Read_All(int *AI_value)
{
ADC_done = 0;
// Using the instruction, students complete Reading ADC
}

● Nhóm hàm xuất tín hiệu Analog (AO Function)


Cho trước hàm “AO_Init”. Sinh viên thực hiện tính toán giá trị Analog cần thiết trong
hàm “AO_Write_ALL” để xuất tín hiệu Analog. Gợi ý, biến con trỏ AO_value gồm 2 giá trị
tương ứng với 2 kênh DAC, các giá trị này có giới hạn từ 0 -> 3.3 và DAC có độ phân giải là
12bits, sinh viên hãy thực hiện tính hai giá trị DAC cần thiết và gán vào biến “AO_set”.
/* AO Function */
void AO_Init(void)
{
float AO_value[2] = {0.0, 0.0};
AO_Write_All(AO_value);
HAL_DAC_Start(&hdac1,DAC_CHANNEL_2);
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);
}
void AO_Write_All(float *AO_value)
{
uint16_t AO_set[2]= {0,0};
// Using the instruction, students calculate the output analog value
HAL_DAC_SetValue(&hdac1,DAC_CHANNEL_1,DAC_ALIGN_12B_R,(uint32_t) AO_set[0]);
HAL_DAC_SetValue(&hdac1,DAC_CHANNEL_2,DAC_ALIGN_12B_R,(uint32_t) AO_set[1]);
}
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
● Hai nhóm hàm “Counter Function”, “Sample Timer Function” dưới đây cho trước, sinh
viên nhập vào kế tiếp để bổ sung hoàn chỉnh các hàm cần thiết cho vi điều khiển.
/* Counter Function */
void Counter_Init(void)
{
HAL_TIM_Encoder_Start(&htim19, TIM_CHANNEL_1);
}
uint32_t Counter_Read(void)
{
uint32_t counter = TIM19->CNT;
return counter;
}
void Counter_Reset(void)
{
TIM19->CNT = 0;
}

/* Sample Timer Function */


void Sample_Timer_Init(void)
{
Sample_Timer_Set_Period(50);
HAL_TIM_Base_Start_IT(&htim6);
}
void Sample_Timer_Set_Period(uint32_t Ts_ms)
{
Ts_ms = Ts_ms*2 -1;
TIM6->ARR = Ts_ms;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{
if (htim->Instance == TIM6)
Sample_Timer_Interrupt();
}

❖ Lập trình chương trình chính


Sinh viên lập trình đoạn code chạy chính trong chương trình. Trong phần CODE BEGIN
2, sinh viên gọi các hàm “Init” sau:
DO_Init();
AO_Init();
Counter_Init();
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
Sample_Timer_Init();

Trong hàm while, khoảng giữa CODE BEGIN 3, sinh viên lập trình đoạn chương trình
sau. Sinh viên tìm hiểu và giải thích ý nghĩa của toàn bộ đoạn code này.
if(usb_tx_flag)
{
usb_tx_flag =0;//Reset flag
uint8_t DI_value = 0;
uint32_t C0_value;
int AI_value[2] = {0,0};

//Call function get all data DI, Counter, AI


DI_value = DI_Read_All();
C0_value = Counter_Read();
AI_Read_All(AI_value);

//Push all data in tx buffer


/* DI */
usb_tx_buffer[0] = DI_value;
/* Counter */
usb_tx_buffer[1] = (uint8_t)(C0_value >> 24);
usb_tx_buffer[2] = (uint8_t)(C0_value >> 16);
usb_tx_buffer[3] = (uint8_t)(C0_value >> 8);
usb_tx_buffer[4] = (uint8_t)(C0_value);
/* AI1 */
usb_tx_buffer[5] = (uint8_t)(AI_value[0] >> 24);
usb_tx_buffer[6] = (uint8_t)(AI_value[0] >> 16);
usb_tx_buffer[7] = (uint8_t)(AI_value[0] >> 8);
usb_tx_buffer[8] = (uint8_t)(AI_value[0]);
/* AI2 */
usb_tx_buffer[9] = (uint8_t)(AI_value[1] >> 24);
usb_tx_buffer[10] = (uint8_t)(AI_value[1] >> 16);
usb_tx_buffer[11] = (uint8_t)(AI_value[1] >> 8);
usb_tx_buffer[12] = (uint8_t)(AI_value[1]);
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS,usb_tx_buffer,13);
}
if (usb_rx_flag)
{
int i;
usb_rx_flag = 0;
switch (usb_rx_buffer[0])/* cmd id */
{
case 'N':/* DO, AO */
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
{
//DO
DO_Write_All(&usb_rx_buffer[1]);
//AO
float AO_value[2] = {0.0, 0.0};
AO_value[0] =
((float)usb_rx_buffer[9]*256+(float)usb_rx_buffer[10])/1000;
AO_value[1] =
((float)usb_rx_buffer[11]*256+(float)usb_rx_buffer[12])/1000;
AO_Write_All(AO_value);
//reset Counter
if (usb_rx_buffer[13] == 'R')
Counter_Reset();

break;
}
case 'F':/* pwm frequency */
{
uint32_t DO_pwm_frequency[3] = {0,0,0};
for(i=0;i<3;i++)
DO_pwm_frequency[i]= (uint32_t)(usb_rx_buffer[i+1]);

DO_pwm_set_frequency(DO_pwm_frequency);
break;
}
case 'T':/* sample time */
{
uint16_t Ts_ms = 1;
Ts_ms = ((int)usb_rx_buffer[1]<<8) + (int)usb_rx_buffer[2];
Sample_Timer_Set_Period(Ts_ms);
break;
}
default:
break;
}
}

❖ Biên dịch chương trình và nạp xuống vi điều khiển

Nhấn Ctrl + S để save chương trình, click vào biểu tượng trên thanh công cụ hoặc
nhấn F7 để biên dịch chương trình. Nếu biên dịch thành công, cửa sổ Build Output sẽ hiện thông
báo tương tự hình bên dưới.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

Nhấn F8 hoặc nhấn vào biểu tượng để nạp chương trình xuống vi điều khiển. Sau
đó sinh viên tắt nguồn vi điều khiển bằng switch (bên cạnh đèn nguồn sáng ở giữa board, nhìn
hình 1)trên board rồi mở lại.
III. Bài thí nghiệm 3: Tạo window form app C#
❖ Tạo project mới:

❖ Add Reference (Thư viện) cho Window Form:

- Chọn Browse sau đó kiếm theo đường link


C:\Program Files\LibUsbDotNet\LibUsbdotnet.dll. Đường dẫn “C:\Program Files” này
còn tùy thuộc vào vị trí sinh viên chọn vị trí lưu khi cài đặt thư viện trên máy tính
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

❖ Tạo giao diện GUI


● Tạo groupbox Connection
Trong cửa sổ Toolbox bên tay trái, chọn tab Common Controls và kéo thả các Button,
Label, Textbox để tạo thành giao diện như hình sau:

Đặt thuộc tính Name của các textbox lần lượt là: txtProductName, txtVendorId,
txtProductId, txtManufacturer. Đặt thuộc tính Name của Button Connect là btnConnect.
- Khai báo thư viện
using LibUsbDotNet;
using LibUsbDotNet.Info;
using LibUsbDotNet.Main;
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
- Khai báo biến toàn cục cho kết nối USB
namespace HIF__
{
public partial class Form1 : Form
{
#endregion variable
public Form1()
{
InitializeComponent();
}

#region Declaring Global Variable


public static UsbDevice myUsbDevice, myUsbDevice_temp;
UsbEndpointReader reader;
UsbEndpointWriter writer;
IAsyncResult result;
#endregion Declaring Global Variable
}
}

❖ Chương trình con cần thiết để thiết lập kết nối và gửi nhận dữ liệu:
#region USB_DATA_RECEIVER_INIT
void USB_DATA_RECEIVER_INIT()
{
IUsbDevice wholeUsbDevice = myUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
wholeUsbDevice.SetConfiguration(1);
wholeUsbDevice.ClaimInterface(0);
}
// Open usb endpoint reader and writer
reader = myUsbDevice.OpenEndpointReader(ReadEndpointID.Ep01);
writer = myUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep01);
// Set Interrupt service routine for reader complete event
reader.DataReceived += (OnRxEndPointData);
reader.DataReceivedEnabled = true;
}
#endregion USB_DATA_RECEIVER_INIT

#region USB DATA RECEIVER INTERRUPT SERVICE ROUTINE


Action<byte[]> UsbReceiverAction;
private void OnRxEndPointData(object sender, EndpointDataEventArgs e)
{
UsbReceiverAction = UsbReceiverActionFunction;
if ((myUsbDevice.IsOpen) && (reader != null))
{
result = this.BeginInvoke(UsbReceiverAction, e.Buffer);
}
}

private void UsbReceiverActionFunction(byte[] input)


{
// Dữ liệu nhận sẽ lưu trong chuỗi input và sẽ xử lý số liệu tại đây
}
#endregion USB DATA RECEIVER INTERRUPT SERVICE ROUTINE
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
#region USB EXIT
private void Usb_exit()
{
reader.DataReceivedEnabled = false;
reader.DataReceived -= (OnRxEndPointData);
this.EndInvoke(ketthuc);
reader.Dispose();
writer.Dispose();
if (myUsbDevice != null)
{
if (myUsbDevice.IsOpen)
{
IUsbDevice wholeUsbDevice = myUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
wholeUsbDevice.ReleaseInterface(0);
}
myUsbDevice.Close();
}
myUsbDevice = null;
UsbDevice.Exit();
}
}
#endregion USB EXIT

❖ Chương trình cho nút nhấn Connect


private void btnconnection_Click(object sender, EventArgs e)
{
// Sinh vien tu them chuong trinh ket noi voi DAQ card
if (btnconnection.Text == "Connect")
{
if (myUsbDevice == null)
{
UsbRegDeviceList allDevices = UsbDevice.AllDevices;
foreach (UsbRegistry usbRegistry in allDevices)
{
if (usbRegistry.Open(out myUsbDevice))
{
txtProductName.Text = myUsbDevice.Info.ProductString;
txtVendorId.Text =
myUsbDevice.Info.Descriptor.VendorID.ToString();
txtProductId.Text =
myUsbDevice.Info.Descriptor.ProductID.ToString();
txtManufacturer.Text =
myUsbDevice.Info.ManufacturerString;
USB_DATA_RECEIVER_INIT();
btnconnection.Text = "Disconnect";
timerSend.Enabled = true;
}
}
}
if (myUsbDevice == null)
{
MessageBox.Show("Device Not Found !!!", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
{
Usb_exit();
btnconnection.Text = "Connect";
txtProductName.Text = "";
txtVendorId.Text = "";
txtProductId.Text = "";
txtManufacturer.Text = "";
txtPWM0.Text = "";
txtPWM1.Text = "";
txtPWM3.Text = "";
txtPWM6.Text = "";
txtPWM7.Text = "";
txtAI0.Text = "";
txtAI1.Text = "";
txtCounter0.Text = "";
timerSend.Enabled = false;
}
}

❖ Form Closed
Chọn vào sự kiện để viết đoạn chương trình đóng ứng dụng.

private void Form1_FormClosing(object sender, FormClosingEventArgs e)


{
if (MessageBox.Show("Do you want to exit ?", "Confirmation",
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{

}
else
{
e.Cancel = true;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
try
{
Usb_exit();
Application.Exit();
}
catch
{

}
}
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

❖ Kết quả kết nối

❖ Gửi nhận dữ liệu


a. Frame truyền dữ liệu
Frame truyền nhận dữ liệu bao gồm một byte đầu tiên là chiều dài frame (không kể
byte độ dài), byte thứ hai là mã lệnh dạng kí tự ASCII, các byte tiếp theo là dữ liệu.
Index 0 1 2..N
Meaning Length byte: N CMD ID byte: ‘N’, ‘T’, ‘F’,… Data bytes
b. Giao diện chương trình
Từ thanh Toolbox, thêm vào các Button, Textbox, Checkbox, OvalShape, Label để tạo
thành giao diện sau:

Kéo một đối tượng Timer từ thanh Toolbox vào giao diện, đặt thuộc tính Name của Timer
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
là TimerSend.
Thay đổi thuộc tính Name của các đối tượng như sau:
- Checkbox ứng với Q0.0-Q0.7: chbDO0 - chbDO7
- Checkbox ứng với label PWM để chọn chế độ PWM hay GPIO: chbPWM0,
chbPWM1, chbPWM3, chbPWM6, chbPWM7.
- Textbox ứng với label Duty để cài đặt chu kì nhiệm vụ trong chế độ PWM, giá trị
nhập vào từ 0-100%: txtPWM0, txtPWM1, txtPWM3, txtPWM6, txtPWM7.
- Textbox ứng với label Frequency, giá trị nhập từ 1-255 KHz: txtF0, txtF1, txtF2.
- Button Config Frequency: btnConfigFreq.
- OvalShape để hiện thị DI0-DI7: ovalDI0- ovalDI7.
- Textbox hiển thị AI0-AI2: txtAI0, txtAI1, txtAI2.

- Textbox ứng với Counter: txtCounter0.

- Textbox ứng với label Sample Time để đặt thời gian lấy mẫu trên cardUSB: txtTs.

- Button ứng với label Sample Time: btnTs.

- Textbox ứng với label AO 0: txtAO0.

- Textbox ứng với label AO 1: txtAO1.


c. Chương trình nhận
Khai báo các biến sử dụng để truyền nhận dữ liệu ở đầu chương trình
#region variable
// DIN
byte DIValue;
// DOUT
byte[] DODuty = new byte[8];
byte[] DOValue = new byte[8];
bool[] DOInPWMMode = new bool[8];
// PWM frequency
byte[] FValue = new byte[3];
// AIN gain
double AIGain;
// Sample time
Int16 TsValue;
// AOUT
byte[] AO0ByteValue = new byte[2];
byte[] AO1ByteValue = new byte[2];
// AIN
double[] AIValue = new double[2];
// Counter
Int32 counterValue;
byte resetCounterCmd;
#endregion variable
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

Trong hàm UsbReceiverActionFunction, ta viết đoạn chương trình sau:


/* GET VALUE */
// DIN
DIValue = input[0];
// Counter
byte[] counterValueTmp = new byte[4];
counterValueTmp[3] = input[1];
counterValueTmp[2] = input[2];
counterValueTmp[1] = input[3];
counterValueTmp[0] = input[4];
counterValue = BitConverter.ToInt32(counterValueTmp, 0);
if (counterValue > 32767)
counterValue = counterValue - 65536;
// AIN
int AI0IntValue;
int AI1IntValue;
byte[] AI0ByteValue = new byte[4];
byte[] AI1ByteValue = new byte[4];
AI0ByteValue[3] = input[5];
AI0ByteValue[2] = input[6];
AI0ByteValue[1] = input[7];
AI0ByteValue[0] = input[8];
AI1ByteValue[3] = input[9];
AI1ByteValue[2] = input[10];
AI1ByteValue[1] = input[11];
AI1ByteValue[0] = input[12];
AI0IntValue = BitConverter.ToInt32(AI0ByteValue, 0);
AI1IntValue = BitConverter.ToInt32(AI1ByteValue, 0);

AIValue[0] = (Convert.ToDouble(AI0IntValue) / 4095) * 3.3;


AIValue[1] = (Convert.ToDouble(AI1IntValue) / 4095) * 3.3;
- Để hiển thị giá trị DI nhận được, ta thay đổi màu sắc của OvalShape
/* DISPLAY */
if (Convert.ToBoolean(DIValue & 0x01))
{
ovalDI0.FillColor = Color.Red;
}
else
{
ovalDI0.FillColor = Color.White;
}

Sinh viên tự viết đoạn chương trình tương tự để hiển thị DI1 – DI7.
- Hiển thị giá trị AIN và Counter
txtAI0.Text = AIValue[0].ToString("0.000");
txtAI1.Text = AIValue[1].ToString("0.000");
txtCounter0.Text = counterValue.ToString();

Sinh viên thay đổi giá trị trên các chân DI, AI, quay động cơ để thay đổi giá trị counter
và kiểm tra lại chương trình trên máy tinh có cập nhật những giá trị này.

d. Chương trình gửi

Chương trình gửi sẽ được đặt trong ngắt Timer, ta config Timer và giá trị ban đầu của
các Textbox trong sự kiện Form1_Load.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

private void Form1_Load(object sender, EventArgs e)


{
timerSend.Interval = 200;
timerSend.Enabled = false;
txtTs.Text = "50";
txtF0.Text = "2";
txtF1.Text = "2";
txtF2.Text = "2";
cbEnablePID.Checked = false;
}
Hàm gửi một mảng qua giao tiếp USB từ máy tính tới cardUSB.
private void USBWrite(byte[] buffer)
{
try
{
int bytesWritten;
if ((myUsbDevice.IsOpen) && (writer != null))
writer.Write(buffer, 1000, out bytesWritten);
}
catch (Exception err)
{
MessageBox.Show("Can Not Send Data To USB Device\nDetails: " + err,
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

Viết đoạn chương trình sau trong hàm ngắt timer1_Tick để cập nhật giá trị DO, AO:
● Cài đặt giá trị DO0:
if (DOInPWMMode[0]) // PWM 0
{
DOValue[0] = DODuty[0];
}
else // GPIO 0
{
if (chbDO0.Checked)
DOValue[0] = 100;
else
DOValue[0] = 0;
}

Sinh viên tự viết chương trình cài đặt giá trị cho tín hiệu DO1 – DO7.
● Gửi frame tới USBCard
byte[] data_send = { 14, (byte)'N', DOValue[0], DOValue[1],
DOValue[2], DOValue[3], DOValue[4], DOValue[5],
DOValue[6], DOValue[7], AO0ByteValue[0], AO0ByteValue[1],
AO1ByteValue[0], AO1ByteValue[1], resetCounterCmd };
USBWrite(data_send);
resetCounterCmd = 0;

Chú ý: Sinh viên kết hợp với kiểm tra checkbox PID Mode, nếu chọn chế độ này thì
không gửi các giá trị này cho vi điều khiển để tiện cho Bài thí nghiệm 4 ở dưới.

Viết đoạn chương trình xử lý ngắt txtAO0_TextChanged


private void txtAO0_TextChanged(object sender, EventArgs e)
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
{
int AOIntValue;
if (txtAO0.Text == "")
{
AOIntValue = 0;
}
else
{
double AODoubleValue = Convert.ToDouble(txtAO0.Text);
if (AODoubleValue > 3.3 || AODoubleValue < 0)
{
MessageBox.Show("Ngoài tầm, hãy nhập giá trị từ 0 đến 3.3",
"Warning", MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}
else
{
AOIntValue = (Int16)(AODoubleValue * 1000);
}
}
AO0ByteValue[0] = (byte)(AOIntValue >> 8);
AO0ByteValue[1] = (byte)(AOIntValue);
}

Tương tự sinh viên viết đoạn chương trình xử lý ngắt txtAO1_TextChanged
Sinh viên bật tắt DO trên máy tính và kiểm tra các LED DO trên USBCard. Nối chân
𝑉𝑜𝑢𝑡
AO1 với AI1, AO2 với AI2 trên panel và kiểm tra giá trị 𝑉𝐴𝐼𝑁 =
2

Viết đoạn chương trình sau trong hàm ngắt chbPWM0_CheckedChanged


DOInPWMMode[0] = chbPWM0.Checked;

Tương tự sinh viên thực hiện cho các sự kiện của các Checkbox chọn DO còn lại.
Ta viết đoạn chương trình sau trong hàm ngắt txtPWM0_TextChanged
if (txtPWM0.Text == "")
{
DODuty[0] = 0;
}
else
{
Int16 DODutyTmp = Convert.ToInt16(txtPWM0.Text);
if (DODutyTmp < 0 || DODutyTmp > 100)
{
MessageBox.Show("Ngoài tầm, hãy nhập giá trị từ 0 đến 100",
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
DODuty[0] = (byte)(DODutyTmp);
}
}

Tương tự sinh viên thực hiện cho các Textbox của PWM. Sinh viên thay đổi số trong
trong Textbox PWM và quan sát độ sáng đèn DO trên USBcard.
Ta viết đoạn chương trình trong hàm ngắt txtF0_TextChanged
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
if (txtF0.Text == "")
{
MessageBox.Show("Hãy nhập giá trị từ 1 đến 255", "Warning",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
Int16 FValueTmp = Convert.ToInt16(txtF0.Text);
if (FValueTmp < 1 || FValueTmp > 255)
{
MessageBox.Show("Ngoài tầm, hãy nhập giá trị từ 1 đến 255",
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
FValue[0] = (byte)FValueTmp;
}
}

Tương tự sinh viên viết tiếp cho các sự kiện txtF1_TextChanged, txtF2_TextChanged

Viết đoạn chương trình trong hàm ngắt txtTs_TextChanged


if (txtTs.Text == "")
{
MessageBox.Show("Hãy nhập giá trị từ 50 đến 30000", "Warning",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
Int16 TsValueTmp = Convert.ToInt16(txtTs.Text);
if (TsValueTmp < 1 || TsValueTmp > 30000)
{
MessageBox.Show("Ngoài tầm, hãy nhập giá trị từ 1 đến 30000",
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
TsValue = TsValueTmp;
}
}

Viết chương trình xử lý sự kiện nhấn nút Config Frequency, Config Ts và Reset Counter
private void btnConfigFreq_Click(object sender, EventArgs e)
{
byte[] data_send = { 4, (byte)'F', FValue[0], FValue[1], FValue[2] };
USBWrite(data_send);
}
private void btnTs_Click(object sender, EventArgs e)
{
byte[] data_send = { 3, (byte)'T', 0, 0 };
data_send[2] = (byte)(TsValue >> 8);
data_send[3] = (byte)(TsValue);
USBWrite(data_send);
}
private void resetC0_Click(object sender, EventArgs e)
{
resetCounterCmd = (byte)'R';
}

Thay đổi thời gian lấy mẫu lần lượt là 1000ms, 10ms và quan sát tốc độ thay đổi giá trị
trong textbox AIN. Quay động cơ về vị trí 0 và nhấn Reset Counter, kiểm tra giá trị counter.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài

IV. Bài Thí nghiệm 4: Điều khiển vị trí động cơ bằng bộ điều khiển PID
Trong bài thí nghiệm này, ta sử dụng cầu H BTS7960 để điều khiển động cơ DC động cơ.
Nguyên lý hoạt động của cầu H BTS7960:
- PULSE1 = 1 và PULSE2 = 0: động cơ quay thuận
- PULSE1 = 0 và PULSE2 = 1: động cơ quay nghịch
- Cả 2 PULSE bằng 0 hoặc 1: động cơ dừng lại.

Chú ý: để điều khiển động cơ, trên panel ta nối chân PLS1, PLS2 với PLS1, PLS2 trên
mô hình động cơ. Trên động cơ có gắn nối tiếp Enocder nhằm xác định vị trí của động cơ. Sinh
viên cần nối 2 ngõ ra A và B trên động cơ tương ứng với A và B trên panel để vi điều khiển đọc
tín hiệu Encoder. Sinh viên không nối dây vào các đầu nối màu đen bên dưới vì những chỗ
này đã được nối sẵn với các chân tín hiệu ở vi điều khiển.
Sinh viên nối 2 dây nguồn 5V và 12V tương ứng và 1 dây GND bên mô hình động cơ
với panel để cấp nguồn cho động cơ và Encoder.

Cài đặt giá trị PWM0, PWM1 là 1kHz, thời gian lấy mẫu của USB card là 10ms. Viết
thêm đoạn chương trình gửi giá trị điều khiển xung PWM sau vào cuối hàm ngắt nhận
UsbReceiverActionFunction.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
/* CALCULATE PID */
currentPos = counterValue;
// Write your code here to calculate pidOutput from currentPos

/* OUTPUT PID VALUE */


byte[] data_send = { 14, (byte)'N', 0, 0, DOValue[2], DOValue[3], DOValue[4],
DOValue[5], DOValue[6], DOValue[7], AO0ByteValue[0], AO0ByteValue[1],
AO1ByteValue[0], AO1ByteValue[1], resetCounterCmd };

if (pidOutput > 0)
{
data_send[2] = (byte)pidOutput;
}
else
{
pidOutput = -pidOutput;
data_send[3] = (byte)pidOutput;
}

USBWrite(data_send);
resetCounterCmd = 0;

Chú ý: sinh viên kết hợp kiểm tra điều kiện checkbox PID mode.
Sinh viên tự tạo các textbox để đặt giá trị cần điều khiển, các thông số của bộ điều khiển
PID và bổ sung chương trình tính giá trị PID vào đoạn chương trình ở trên dựa trên công thức
đã cho ở dưới.
1 𝐾𝑑
𝑢(𝑘) = 𝐾𝑝 𝑒(𝑘) + 𝐾𝑖 𝑇𝑠 (𝑒(𝑘) + 𝑒(𝑘 − 1)) + (𝑒(𝑘) − 2𝑒(𝑘 − 1) + 𝑒(𝑘 − 2))
2 𝑇𝑠
Nội dung Báo cáo thí nghiệm:
- Giải thích chương trình trên USBCard và máy tính trong các thí nghiệm 1 và 2.
- Báo cáo chương trình PID điều khiển vị trí động cơ.
Bài TN4: Lập trình card USB Biên soạn: TS. Nguyễn Trọng Tài
Bảng nhận xét, đánh giá của GV
Thông tin Sinh viên:
Nhóm:
Họ và Tên SV:
MSSV:
Các nhiệm vụ và nội dung thực hiện trong buổi thí nghiệm:

Đánh giá của GV:

STT Tiêu chí Mức 1 Mức 2 Mức 3 Mức 4 Mức 5


1 Chuẩn bị bài TN
2 Mức độ hoàn thành BTN
3 Mức độ nắm bắt nội dung thí nghiệm
4 Mức độ giải quyết các bài toán tại lớp
của GVHD
5 Nội dung báo cáo thí nghiệm
6 Mức độ trả lời các câu hỏi trong BTN
7 Tính sáng tạo giải thuật
8 Liên kết các thành viên trong nhóm
Các ý kiến khác:
Revision: rev 1
Number:

Date: 4/18/2018 Time: 12:15:39 AM Sheet 1 of 1


A0 0 8 B0
A0 B0 File: D:\hoc hanh\electronic\project\others\card_DLDKMT\CardUSBv2_2\CardUSB_v1.SchDoc
PA1 PB1
PA1 PB1
PA2 1
PA2 PB2
PA3 B3 GND
PA4 11 PA3 PB3 9
PB4 2 3 4 5 6 7 8
PA4 PB4 SWDIO
PA5 PB5
PA5 PB5
PA6 2 0 PB6
PA6 PB6
P
A8 PA9 3 9 B7
A8
PA10 PB8 C1 1
PA9
PA11 PB9 C2 1
PA10 2A
PA12 4 0 PB14
PA11 2 LM358
SWDIO 2B
PA12 IN_8 B9 OUT_1 IM15_CH1 B14
SWCLK AI1 1 R1 AI2 1 R2 LM358
PA13 DIN_7 PB8 DOUT_2 TIM15_CH2 PB15
PA15 5
PA14 2 100K 2 100K 3A PE9 DOUT_3 PE8
SC_IN LM358
R3 2 R4 2 DIN_3 PB5 DOUT_4 PA6
F0-OSC_IN OSC_OUT
R5 2 AO1 DIN_4 PA15 DOUT_5 PA1
C4 2 DIN_5 PF7 DOUT_6 PA0
C13 PF1-OSC_OUT PC14- F6 6 7 DIN_2 PF6 DOUT_7 PA3
OSC32_IN PF6 PC15- GND 100K 100K DIN_6 PA8 DOUT_8 PA2
6R
OSC32_OUT PF7 6 D1 7 D2
E8 NRST
1
PE9 21
IN_1 DC_IN8 B0 OUT_1 AC1_OUT1 A4
AIN_2 ADC_IN9 PB1 AOUT_2 DAC1_OUT2 PA5
8 A
100k O DA 2C2_SDA A10 SB_DM A11
1 SCL I2C2_SCL PA9 USB_DP PA12
BAT U1B
8
104
A NCA_1 IM19_CH1 B6 TM_TX SART2_TX B3
7 VDD_1 ENCB_1 TIM19_CH2 PB7 STM_RX USART2_RX PB4

REFSD+ 23
9 VDDA/VREF+ VSSA/VREF- 8
STM32F373CCT6 3B
1 LM358
I3 6 OUT_2 5
VIN+ SDA 4 SDA 1 R10 2 AO2
AI4
VIN- SCL 3 SCL 1
V
DDA 5 VDD VSS 2
6R
1

C13 C14 C15 C16 C17 C18 C19 C20 12


10
11 104 1u
104

R12 2
GND

You might also like