[RYA2013] Giới thiệu cơ bản về sử dụng ADC của TM4C123

cooliovato

Cố Vấn CLB
Staff member
Bài viết mang tính sơ lược và không chuyên, nếu có sai sót mong các bạn thông cảm và các cao nhân chỉ bảo thêm :1cool_byebye::)

Các nội dung sau đây là những phần được-cho-là-cơ-bản =)) khi làm việc với ADC của TM4C123 (hoặc LM4F120 cũ) được trích từ:
+ Datasheet, userguide: http://www.ti.com/product/tm4c1230h6pm
1/ Sơ lược về ADC của TM4C123H6PM:
+ 2 module ADC 12 bits​
+ 12 kênh ADC input​
+ Lấy mẫu kiểu single-ended hoặc differential​
+ Tần số lấy mẫu tối đa 1MSPS (1 mega samples per second)​
+ Điện áp tham chiếu Vref = 3.3V​
+ Kích hoạt lấy mẫu bằng processor, timer, analog comparators hoặc GPIO​
+ 4 "sequence" lấy mẫu (ADC sample sequencers)​
2/ Về ADC sample sequencers (SS):
Sequence (tạm dịch là "chuỗi mẫu") được dùng để giúp cho việc lấy mẫu từ nhiều kênh input tiện lợi hơn, hoặc có thể dùng để lấy nhiều mẫu trên cùng một kênh input. Có 4 sequence:
+ SS3: mỗi lần lấy tối đa 1 mẫu​
+ SS1, SS2: mỗi lần lấy tối đa 4 mẫu​
+ SS0: mỗi lần lấy tối đa 8 mẫu​
Ví dụ các bạn muốn lấy mẫu ADC từ 4 kênh (4 LED thu hồng ngoại chẳng hạn) thì có thể dùng SS1 hoặc SS2 và config để lấy mỗi lần 4 mẫu từ 4 kênh này (1 mẫu từ mỗi kênh).​
3/ Ví dụ về config cho ADC lấy mẫu từ 4 kênh:
Code:
//include header files
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/gpio.h"
 
int main(void)
{
  //mảng chứa giá trị mẫu mỗi lần lấy, ở đây ta cần lấy mỗi lần 4 mẫu
  //To do: đổi kích thước của mảng tùy theo số mẫu muốn lấy
  uint32_t ui32ADC0Value[4];
 
  //Set system clock
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
 
  //Enable ADC0
  SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
 
  //Enable port E và config cho các chân PE0-PE3 thành chân ADC
  //To do: đổi sang chân GPIO theo nhu cầu (cần xem datasheet để biết các chân nào có chức năng ADC)
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
  GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
 
  /*Config cho ADC sample sequencer, ở đây ta dùng SS1, chọn kiểu kích hoạt (trigger) bằng
poccesor, và độ ưu tiên là 0 (ưu tiên cao nhất) */
  //To do: chỉnh lại SS cần dùng, kiểu trigger hoặc độ ưu tiên (nếu dùng nhiều SS)
  ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
 
  /* Config cho 4 step của SS1 (tương ứng với 4 mẫu từ 4 kênh). Ở đây giả sử ta cần lấy mẫu từ  4 kênh
(channel) theo thứ tự 0, 1, 2, 3 tương ứng với các chân AIN0-AIN3 hay PE3-PE0, sau khi  lấy mẫu kênh
cuối sẽ ngừng lấy mẫu và bật cờ ngắt */
  //To do: chỉnh lại kênh (xem datasheet để biết các kênh và chân tương ứng)
  ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH0);
  ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH1);
  ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH2);
  ADCSequenceStepConfigure(ADC0_BASE,1,3,ADC_CTL_CH3|ADC_CTL_IE|ADC_CTL_END);
 
  //Enable SS1
  ADCSequenceEnable(ADC0_BASE, 1);
 
  while(1)
  {
    //Xóa cờ ngắt và kích hoạt lấy mẫu
    ADCIntClear(ADC0_BASE, 1);
    ADCProcessorTrigger(ADC0_BASE, 1);
 
    //Chờ đến khi lấy mẫu xong
    while(!ADCIntStatus(ADC0_BASE, 1, false));
 
    /*Đọc data (giá trị mẫu) lưu vào mảng, thứ tự mẫu trong mảng cũng chính là thứ tự các step (hay
channel) như đã config. Cụ thể là ui32ADC0Value[0] sẽ chứa mẫu của CH0, ui32ADC0Value[1] chứa mẫu
của CH1,... */
    ADCSequenceDataGet(ADC0_BASE, 1, ui32ADC0Value);
  }
}
 

phucuong23192

Thành Viên PIF
//include header files
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/gpio.h"
unsigned long ui32ADC0Value;
unsigned long a;
int main(void)
{
//mảng chứa giá trị mẫu mỗi lần lấy, ở đây ta cần lấy mỗi lần 4 mẫu
//To do: đổi kích thước của mảng tùy theo số mẫu muốn lấy


//Set system clock
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);

//Enable ADC0
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

//Enable port E và config cho các chân PE0-PE3 thành chân ADC
//To do: đổi sang chân GPIO theo nhu cầu (cần xem datasheet để biết các chân nào có chức năng ADC)
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1 );

/*Config cho ADC sample sequencer, ở đây ta dùng SS1, chọn kiểu kích hoạt (trigger) bằng
poccesor, và độ ưu tiên là 0 (ưu tiên cao nhất) */
//To do: chỉnh lại SS cần dùng, kiểu trigger hoặc độ ưu tiên (nếu dùng nhiều SS)
ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);

/* Config cho 4 step của SS1 (tương ứng với 4 mẫu từ 4 kênh). Ở đây giả sử ta cần lấy mẫu từ 4 kênh
(channel) theo thứ tự 0, 1, 2, 3 tương ứng với các chân AIN0-AIN3 hay PE3-PE0, sau khi lấy mẫu kênh
cuối sẽ ngừng lấy mẫu và bật cờ ngắt */
//To do: chỉnh lại kênh (xem datasheet để biết các kênh và chân tương ứng)

ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH2|ADC_CTL_IE|ADC_CTL_END);

//Enable SS1
ADCSequenceEnable(ADC0_BASE, 1);

while(1)
{
//Xóa cờ ngắt và kích hoạt lấy mẫu
ADCIntClear(ADC0_BASE, 1);
ADCProcessorTrigger(ADC0_BASE, 1);
a=0;
//Chờ đến khi lấy mẫu xong
while(!ADCIntStatus(ADC0_BASE, 1, false));

/*Đọc data (giá trị mẫu) lưu vào mảng, thứ tự mẫu trong mảng cũng chính là thứ tự các step (hay
channel) như đã config. Cụ thể là ui32ADC0Value[0] sẽ chứa mẫu của CH0, ui32ADC0Value[1] chứa mẫu
của CH1,... */
ADCSequenceDataGet(ADC0_BASE, 1, &ui32ADC0Value);

a=ui32ADC0Value;
}
}
mình đọc ADC zô chân PE1 sao giá trị ADC lúc cắm tín hiệu ADC vào và không cắm nó chẳng thay đổi gi.@@:-s
 

cooliovato

Cố Vấn CLB
Staff member
phucuong23192 : code của bạn mình nạp thử thì chạy bình thường mà.
Khi debug bạn nhớ click vào "continuous refresh" để debugger cập nhật liên tục giá trị của biến mới thấy nó thay đổi được.
 

phucuong23192

Thành Viên PIF
phucuong23192 : code của bạn mình nạp thử thì chạy bình thường mà.
Khi debug bạn nhớ click vào "continuous refresh" để debugger cập nhật liên tục giá trị của biến mới thấy nó thay đổi được.
ờ. tks ak. để mình xem lại. giá trị của mình khi chưa cắm tín hiệu ADC đã có giá trị rùi, mà giá trị nó chẳng ổn định chút nào. nhảy lung tug:5cool_beat_plaster:
 

nguyenlkdn

Trứng gà
Hi PIF ! Hiện tại mình đang thắc mắc về phần cấu hình điện áp qui chiếu nội của M4F theo như mình biết thì sử dụng hàm ADCReferenceSet(...) để set nhưng mình không biết truyền giá trị như thế nào để có thể cấu hình mức điên áp qui chiếu dương là 1V và âm là 0v.
Thân !
 

honghiep

Cố Vấn CLB
Staff member
Hi PIF ! Hiện tại mình đang thắc mắc về phần cấu hình điện áp qui chiếu nội của M4F theo như mình biết thì sử dụng hàm ADCReferenceSet(...) để set nhưng mình không biết truyền giá trị như thế nào để có thể cấu hình mức điên áp qui chiếu dương là 1V và âm là 0v.
Thân !
Bạn xem ở trang 35, DiverLib User's Guide có nói: The ADC reference is set as specified by ui32Ref . It must be one of ADC_REF_INT,
ADC_REF_EXT_3V, or ADC_REF_EXT_1V for internal or external reference. If
ADC_REF_INT is chosen, then an internal 3V reference is used and no external reference
is needed. If ADC_REF_EXT_3V is chosen, then a 3V reference must be supplied to the
AVREF pin. If ADC_REF_EXT_1V is chosen, then a 1V external reference must be supplied
to the AVREF pin.
Để có được áp quy chiếu 1V thì phải cấp Vref ngoài. Vref nội chỉ có 3V thôi
 
Top