[cần giúp đỡ] ADC + UART hiển thị Terminal

darknight2804

Trứng gà
Mình dùng Hercules Terminal để hiển thị ADC thông qua UART, code của mình nhận tín hiệu gửi lên, nhưng sao mặc dù đã cộng thêm 0x30 vào biến đọc ADC rồi, nhưng nó chỉ toàn hiện kí tự lạ mà thôi, kiểu nó thế này

Code:
$$$$$$#$$$$$$$$$$$$#$$$$$$$$$$$$$$$$$$$$$$$$$#$#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
Các bạn xem thử code của mình nhé :
Code:
/***** Include directory file *****/
#include <pic.h>
#include <htc.h>
 
/***** PIC special fuction configuration *****/
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_OFF) ; //1st config. Word
 
__CONFIG(BOR4V_BOR21V); //2st config.
 
/***** Define *****/
#define  _XTAL_FREQ  20000000
 
#define delay_ms(x) __delay_ms(x)
#define delay_us(x) __delay_us(x)
 
void pic_init(void);
void uart_transmit(unsigned char data);
unsigned long e, abc;
 
/***** Sub function *****/
void pic_init(void)
{ 
    TRISA = 1;
    TRISC6 = 1;                  // TX Pin
    TRISC7 = 1;                  // RX Pin
 
    TRISD = 0;
    PORTD = 0xFF;
    SPBRG = 129;    // Set baud rate as 9600 baud
    BRGH = 1;      // Baud rate high speed option
    TXEN = 1;      // Enable transmission
    TX9 = 0;        // 8-bit transmission
    RX9 = 0;        // 8-bit reception
    CREN = 1;      // Enable reception
    SPEN = 1;      // Enable serial port
}
 
void ADC_init()
{
  //AN0 is analog
  ANSEL=1;
  ANSELH=0;
  //ADC conversion clock source = Fosc/32
  ADCS0=0; 
  ADCS1=1;
  // Vref = VCC = 5V
  VCFG0=0; 
  VCFG1=0;
  // Select channel 0
  CHS0=0;   
  CHS1=0;
  CHS2=0;
  CHS3=0;
  //Result formatting: Right justified
  ADFM=1;   
  // Turn on ADC module
  ADON=1;   
  __delay_ms(1); // delay for initiation of module ADC
 
}
 
void int_init()
{
    GIE = 1;  //Global Interrupt Enable
  PEIE = 1;  //Peripheral Interrupt Enable
  ADIE = 1;  //ADC Interrupt Enable
  ADIF = 0;  //Clear ADC Interrupt Flag
}
 
void interrupt isr()
{
  if (PEIE && ADIE && ADIF) // Check if conversion is complete
    {
      e=(ADRESH<<8|ADRESL);
      ADIF = 0;  //Clear ADC Interrupt Flag
      __delay_ms(100);
  }
}
 
void uart_transmit(unsigned char data)
{
    while(!TXIF);
    TXREG = data;
}
 
/***** Main function *****/
void main(void)
{
    pic_init();
    ADC_init();
    int_init();
    delay_ms(500);
    while (1)
  {
            __delay_us(50);
            uart_transmit(e+0x30);
            GO_DONE=1;
            delay_ms(50);
        }
}
Các bạn giải quyết lỗi này hộ mình với nhé, cảm ơn !

Sẵn tiện cho mình hỏi, ADC như thế này đã kèm lấy mẫu chưa nhỉ...?
 

honghiep

Cố Vấn CLB
Staff member
Mình dùng Hercules Terminal để hiển thị ADC thông qua UART, code của mình nhận tín hiệu gửi lên, nhưng sao mặc dù đã cộng thêm 0x30 vào biến đọc ADC rồi, nhưng nó chỉ toàn hiện kí tự lạ mà thôi, kiểu nó thế này

Code:
$$$$$$#$$$$$$$$$$$$#$$$$$$$$$$$$$$$$$$$$$$$$$#$#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
Các bạn xem thử code của mình nhé :
Code:
/***** Include directory file *****/
#include <pic.h>
#include <htc.h>
 
/***** PIC special fuction configuration *****/
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_OFF) ; //1st config. Word
 
__CONFIG(BOR4V_BOR21V); //2st config.
 
/***** Define *****/
#define  _XTAL_FREQ  20000000
 
#define delay_ms(x) __delay_ms(x)
#define delay_us(x) __delay_us(x)
 
void pic_init(void);
void uart_transmit(unsigned char data);
unsigned long e, abc;
 
/***** Sub function *****/
void pic_init(void)
{
    TRISA = 1;
    TRISC6 = 1;                  // TX Pin
    TRISC7 = 1;                  // RX Pin
 
    TRISD = 0;
    PORTD = 0xFF;
    SPBRG = 129;    // Set baud rate as 9600 baud
    BRGH = 1;      // Baud rate high speed option
    TXEN = 1;      // Enable transmission
    TX9 = 0;        // 8-bit transmission
    RX9 = 0;        // 8-bit reception
    CREN = 1;      // Enable reception
    SPEN = 1;      // Enable serial port
}
 
void ADC_init()
{
  //AN0 is analog
  ANSEL=1;
  ANSELH=0;
  //ADC conversion clock source = Fosc/32
  ADCS0=0;
  ADCS1=1;
  // Vref = VCC = 5V
  VCFG0=0;
  VCFG1=0;
  // Select channel 0
  CHS0=0; 
  CHS1=0;
  CHS2=0;
  CHS3=0;
  //Result formatting: Right justified
  ADFM=1; 
  // Turn on ADC module
  ADON=1; 
  __delay_ms(1); // delay for initiation of module ADC
 
}
 
void int_init()
{
    GIE = 1;  //Global Interrupt Enable
  PEIE = 1;  //Peripheral Interrupt Enable
  ADIE = 1;  //ADC Interrupt Enable
  ADIF = 0;  //Clear ADC Interrupt Flag
}
 
void interrupt isr()
{
  if (PEIE && ADIE && ADIF) // Check if conversion is complete
    {
      e=(ADRESH<<8|ADRESL);
      ADIF = 0;  //Clear ADC Interrupt Flag
      __delay_ms(100);
  }
}
 
void uart_transmit(unsigned char data)
{
    while(!TXIF);
    TXREG = data;
}
 
/***** Main function *****/
void main(void)
{
    pic_init();
    ADC_init();
    int_init();
    delay_ms(500);
    while (1)
  {
            __delay_us(50);
            uart_transmit(e+0x30);
            GO_DONE=1;
            delay_ms(50);
        }
}
Các bạn giải quyết lỗi này hộ mình với nhé, cảm ơn !

Sẵn tiện cho mình hỏi, ADC như thế này đã kèm lấy mẫu chưa nhỉ...?
Bạn để ý là biến "e" đang lưu giá trị ADC đọc về. Giá trị ADC đọc về gồm 10 bit, hiện được lưu trong biến kiểu long
Đối số đưa vào của hàm truyền UART kiểu unsigned char (8 bit). Vì vậy khi đưa giá trị kiểu long vào, kiểu sẽ bị ép, giá trị không còn đúng nữa.
Việc cộng 0x30 vào thông thường để lấy mã ASCII của một số, vì vậy "e" chỉ có thể nằm trong tầm từ 0 -> 9.
Việc lấy mẫu ADC được thực hiện mỗi khi GO_DONE được gán = 1
 

darknight2804

Trứng gà
Thành thật cảm ơn lời giải thích của bạn, mình đã thử đổi biến e thành int, cho e*1000/1023 thì ra được kết quả, nhưng chỉ ra được 1 chữ số. Mình cũng chưa hiểu lắm, mong bạn chỉ cách sửa code cho hợp lý. Cảm ơn
 

honghiep

Cố Vấn CLB
Staff member
Thành thật cảm ơn lời giải thích của bạn, mình đã thử đổi biến e thành int, cho e*1000/1023 thì ra được kết quả, nhưng chỉ ra được 1 chữ số. Mình cũng chưa hiểu lắm, mong bạn chỉ cách sửa code cho hợp lý. Cảm ơn
Việc gửi dữ liệu qua UART bạn cần lưu ý về tầm giá trị, kiểu dữ liệu gửi lên. Với các thiết lập như trên, mỗi lần bạn sẽ gửi 8-bit qua UART bằng lệnh
uart_transmit(data). Nếu dữ liệu bạn gửi lên nhiều hơn 8-bit, bạn cần tách dữ liệu thành nhiều byte rồi gửi từng byte đi
 
Top