Cần giúp Chống nhiễu cho ADC

huunho

Thạc sỹ
#1
Chào các bạn.
Mình đang đọc ADC 1 kênh của stm32f103c8t6, quá trình đọc thì bình thường nhưng giá trị trả về nhảy linh tinh ở 2 số cuối. cụ thể ADC 12 bít thì giá trị lớn nhất trả về là 4096 thì giá trị này cứ nhảy linh tinh ở 2 số cuối là 96. nếu gắn AIN0 vào VCC thì đọc dc là 4030, còn gắn vào GND thì đọc dc là 0000 thì ko nhảy, nhưng các giá trị trung gian thì nhảy rất nhanh do nhiễu.
Ai đã làm qua rồi xin cho mình lời khuyên để khử nhiễu. cám ơn mọi người đã đọc
 

Đính kèm

BuiBachTuanAnh

Quản trị viên
Thành viên BQT
#2
Hiện tượng xử lý nhiễu thì muôn thủa, mỗi project có cách xử lý khác nhau và tuỳ vào từng điều kiện hoạt động của mạch. Nhiễu ADC cũng vậy, tuy nhiên trước hết phải tuân thủ nguyên tắc theo khuyến cáo của nhà sản xuất đã.
F49901CC-CAA0-4468-A275-1044847895D5.png

F7D9C67D-9C6E-433F-A338-54382BE849E7.png
Với chú ý một số điểm sau:
- Đầu vào Analog cần được bọc chống nhiễu.
- Vref cần được cấp chuẩn. Như bọn tư bản nó hay dùng một con IC chuyên dụng để cấp nguồn riêng cho thằng này.
Mình lâu quá rồi ko làm và cũng không làm nhiều nên góp ý với bạn chút cho rôm rả thôi :)
 

huunho

Thạc sỹ
#3
cám ơn bạn quan tâm.
Mình tét theo mạch trên thì thấy nhiễu giảm đi 30% , nên vẫn chưa ổn. Mình đã tính trung bình 100 giá trị ADC liên tiếp để lấy ra giá trị gần đúng nên cũng khá ổn rồi. Bạn có biết cách xây dựng bộ lọc kalman thì nói vắn tắt giúp mình?
 

Concept

Kỹ sư
#4
cám ơn bạn quan tâm.
Mình tét theo mạch trên thì thấy nhiễu giảm đi 30% , nên vẫn chưa ổn. Mình đã tính trung bình 100 giá trị ADC liên tiếp để lấy ra giá trị gần đúng nên cũng khá ổn rồi. Bạn có biết cách xây dựng bộ lọc kalman thì nói vắn tắt giúp mình?
Tìm được đoạn clip này nói về giảm nhiễu ADC. Tuy có hơi khác bạn một chút là tác giả lấy 128 giá trị trung bình liên tiếp, giải thuật xem ra có vẻ khá đơn giản nhưng rất thông minh, Bạn xem thử có giúp gì được không ?

Chú ý: Trong phần dưới của clip có đường dẫn để bạn tải về code mẫu...

Nguồn

 
#5
dường như code đính kèm ko giống trong video nhưng mình cũng hiểu ý của chủ video rồi. mình tính trung bình theo kiểu đệ quy để ko tốn ram
 
#6
cụ thể thế này:
void ADC1_2_IRQHandler(void)
{
/* USER CODE BEGIN ADC1_2_IRQn 0 */
//HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
static uint32_t vol[20],k,a;
//uint16_t i;
//k++;
//if(k>99) k=0;
//vol[k] = HAL_ADC_GetValue(&hadc1);
k = a;
a=HAL_ADC_GetValue(&hadc1);
a = (59*k +a)/60;
num2 = a*15840/4096;
num1 = num2 / 10000;
/* USER CODE END ADC1_2_IRQn 0 */
HAL_ADC_IRQHandler(&hadc1);
/* USER CODE BEGIN ADC1_2_IRQn 1 */

/* USER CODE END ADC1_2_IRQn 1 */
}
 
#7
cụ thể thế này:
void ADC1_2_IRQHandler(void)
{
/* USER CODE BEGIN ADC1_2_IRQn 0 */
//HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
static uint32_t vol[20],k,a;
//uint16_t i;
//k++;
//if(k>99) k=0;
//vol[k] = HAL_ADC_GetValue(&hadc1);
k = a;
a=HAL_ADC_GetValue(&hadc1);
a = (59*k +a)/60;
num2 = a*15840/4096;
num1 = num2 / 10000;
/* USER CODE END ADC1_2_IRQn 0 */
HAL_ADC_IRQHandler(&hadc1);
/* USER CODE BEGIN ADC1_2_IRQn 1 */

/* USER CODE END ADC1_2_IRQn 1 */
}
Nhìn code của bạn mình cũng không hiểu nhiều lắm, chắc trình độ mình còn non :-)

Không rõ bạn nhận xét thế nào về giải thuật của đoạn video clip, theo mình từ phút 3:41 của đoạn clip tác giả đã thể hiện một đoạn code mà trong đó, đoạn chương trình không cập nhật lên LCD tức thời giá trị đọc được nếu giá trị này khác so với giá trị trước đó khoảng 1 hay 2 đơn vị ... Thay vào đó chương trình đọc tiếp thêm hai lần nữa, nếu giá trị này vẫn giữ giá trị thay đổi so với 2 chu kỳ đọc trước đó, nó sẽ cập nhật lên LCD còn không bỏ qua coi như nhiễu.

Tất nhiên như tác giả cũng thừa nhận, còn có nhiều giải pháp khác... có thể hay hơn nhưng cũng phải nhìn nhận giải pháp của tác giả khá đơn giản nhưng rất thông minh.

Chúc vui.
 
#8
Cám ơn bạn concept đã góp ý. Bạn quá khiên tốn rồi. trình độ của bạn thì rất nhiều người không bằng. Do ở code trên mình ko giải thích gì nên bạn chưa thấy rõ ràng thôi.
Cụ thể là đoạn code trên là hàm ngắt của ADC1, mỗi khi chuyển đổi ADC xong thì chíp nhảy vào ngắt và tính toán như sau, giá trị adc cũ được giữ lại bởi biến k:
k = a;
còn giá trị adc mới được lưu và biến a
a=HAL_ADC_GetValue(&hadc1);
sau đó giá trị mới chỉ được tính bằng 1/60 kết quả sẽ hiển thị ra màn hình , trong khi kết quả cũ bằng 59/ 60 kết quả , điều này có tác dụng chống nhiễu bằng phần mềm đáng kể và giảm dung lượng ram và các phép toán cồng kềnh:
a = (59*k +a)/60;
kết quả hiển thị trên màn hình khá ổn định:
num2 = a*15840/4096; (điện áp hiển thị trên màn hình led 7 đoạn)

Hiện tại mình gặp vấn đề sau: mình nối trở R1 = 1k vào chân A0 (ADC IN0) với GND, còn trở R2 = 47k nối vào A0 (ADC IN0) với điện áp cần đo. với điện áp mẫu VREF = 3.3V thì điện áp đo được của mạch ADC là
(VREF/R1) *(R2+R1) = (3.3/1)*(47+1)=158.4V
do giá trị tính toán là số nguyên nên ta nhân nó với 100 để có thể tính với số nguyên
158.4 * 100 = 15840
với ADC 12 bít của stm32f103c8t6, giá trị tối đa đọc dc của ADC là 2^12 = 4096 nhưng do tính từ số 0 ở đầu nên chỉ còn 4095
Giả sử giá trị ADC đọc được là a thì điện áp đo được là:
(a/4095)*(VREF/R1)*(R1+R2) = (a/4095)*158.4 V
Nhân kết quả trên với 100 để làm việc với số nguyên, trên màn hình sẽ hiển thị số nguyên:
num1 = 15840*a/4095
ví dụ ADC đo được a = 100 thì trên màn hình hiển thị
num1 = 15840*100/4095 = 386
thì ta cố tình hiểu nó là 3.86V
tất cả các tính toán trên là lý thuyết, còn thực tế lại khác. mình tăng dần điện áp từ 0 đến 5V thì màn hình mới bắt đầu nhích số từ 0000 chuyển sang 0031, tăng lên đến 10V thì hiển thị dc 167( tức 1.67V) 15V hiển thi 282. tức 2.82V
sau đó giảm dần về đến 3v thì màn hình hiển thị 0000.
bạn concept có thể tìm lỗi giúp mình không?
 
#9
Cám ơn bạn concept đã góp ý. Bạn quá khiên tốn rồi. trình độ của bạn thì rất nhiều người không bằng. Do ở code trên mình ko giải thích gì nên bạn chưa thấy rõ ràng thôi.
Cụ thể là đoạn code trên là hàm ngắt của ADC1, mỗi khi chuyển đổi ADC xong thì chíp nhảy vào ngắt và tính toán như sau, giá trị adc cũ được giữ lại bởi biến k:
k = a;
còn giá trị adc mới được lưu và biến a
a=HAL_ADC_GetValue(&hadc1);
sau đó giá trị mới chỉ được tính bằng 1/60 kết quả sẽ hiển thị ra màn hình , trong khi kết quả cũ bằng 59/ 60 kết quả , điều này có tác dụng chống nhiễu bằng phần mềm đáng kể và giảm dung lượng ram và các phép toán cồng kềnh:
a = (59*k +a)/60;
kết quả hiển thị trên màn hình khá ổn định:
num2 = a*15840/4096; (điện áp hiển thị trên màn hình led 7 đoạn)

Hiện tại mình gặp vấn đề sau: mình nối trở R1 = 1k vào chân A0 (ADC IN0) với GND, còn trở R2 = 47k nối vào A0 (ADC IN0) với điện áp cần đo. với điện áp mẫu VREF = 3.3V thì điện áp đo được của mạch ADC là
(VREF/R1) *(R2+R1) = (3.3/1)*(47+1)=158.4V
do giá trị tính toán là số nguyên nên ta nhân nó với 100 để có thể tính với số nguyên
158.4 * 100 = 15840
với ADC 12 bít của stm32f103c8t6, giá trị tối đa đọc dc của ADC là 2^12 = 4096 nhưng do tính từ số 0 ở đầu nên chỉ còn 4095
Giả sử giá trị ADC đọc được là a thì điện áp đo được là:
(a/4095)*(VREF/R1)*(R1+R2) = (a/4095)*158.4 V
Nhân kết quả trên với 100 để làm việc với số nguyên, trên màn hình sẽ hiển thị số nguyên:
num1 = 15840*a/4095
ví dụ ADC đo được a = 100 thì trên màn hình hiển thị
num1 = 15840*100/4095 = 386
thì ta cố tình hiểu nó là 3.86V
tất cả các tính toán trên là lý thuyết, còn thực tế lại khác. mình tăng dần điện áp từ 0 đến 5V thì màn hình mới bắt đầu nhích số từ 0000 chuyển sang 0031, tăng lên đến 10V thì hiển thị dc 167( tức 1.67V) 15V hiển thi 282. tức 2.82V
sau đó giảm dần về đến 3v thì màn hình hiển thị 0000.
bạn concept có thể tìm lỗi giúp mình không?
Có cái gì đó không ổn ở đây :-), đặc biệt ở phần bạn tính từ 3.3 V lên... 158.4V... nó giống như bạn đang suy nghĩ và tính toán về một mạch.... tăng áp DC ... đây là phần mình không hiểu. Phần Vref cho mạch ADC nói chung dường như khác với những gì bạn dùng để tính toán lý thuyết.

Nếu được bạn cho mình xem bản vẽ phần cứng của mạch phân áp thì mình sẽ dễ hình dung hơn.

Mình ít sử dụng STM32 mà chủ yếu chỉ chơi Arduino thôi... nên đành phải tìm trong google vậy... và đây là một trang web mình tìm thấy nguồn https://letanphuc.net/2016/07/stm32f0-adc/. Tác giả trang web có vẻ là người Việt mà sao thấy toàn viết bằng tiếng Anh kể cả các video clip minh họa tác giả cũng giải thích bằng tiếng Anh luôn.

Nhưng thôi bỏ qua chuyện này cái được là trang web này viết rất chi tiết về ADC của STM32 bạn thử xem có giải quyết được gì không.

Rất mong được trao đổi cùng bạn. Chúc vui.
 

Quảng cáo Google