Chức năng của assert_failed...

lam_nguyen56

Sinh viên đại học
#1
Với những người mới làm quen với stm8, sử dụng thư viện chuẩn của ST, hầu hết chúng ta đã từng ít nhất một lần gặp phải lỗi
Error[Li005]: no definition for "assert_failed"... (IAR IDE)
Có nghĩa là chúng ta chưa định nghĩa cho "assert_failed". Sau khi tham khảo google các kiểu hoặc tham khảo các example trong thư viện chúng ta đều nhận ra rằng chương trình chúng ta để chạy được đều phải có đoạn sau
Mã:
#ifdef USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *   where the assert_param error has occurred.
  * @param file: pointer to the source file name
  * @param line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif
Nếu thấy đoạn mã trên rườm rà quá thì đơn giản chỉ cần thế này chương trình vẫn biên dịch và chạy ngon
Mã:
void assert_failed(uint8_t* file, uint32_t line){}
Sau khi chương trình biên dịch thành công và chạy được trên chip ta thường thắc mắc rằng đoạn mã đó dùng để làm gì, ta có thể khai thác nó như thế nào.
Khi chương trình đang thực thi, nhiều trường hợp lỗi xuất hiện do tham số truyền vào hàm vượt quá miền khả dụng (cần phân biệt tham số sai kiểu với sai miền khả dụng). Nếu hàm vẫn được thực thi với tham số ngoài miền khả dụng, nó sẽ kéo theo nhiều lỗi khác mà ta rất khó khăn trong việc lần theo các manh mối để tìm ra nguồn gốc của lỗi (ví dụ hàm có thể truy cập và sửa đổi những vùng nhớ ngớ ngẩn). Do vậy cần phải có một cơ chế dừng chương trình khi khi tham số truyền vào hàm vượt quá miền khả dụng, đồng thời cung cấp cho chúng ta vị trí xảy ra lỗi trong chương trình.
Thư viện chuẩn cung cấp cho chúng ta một cơ chế như vậy. Khi một lỗi "tham số vượt quá miền khả dụng" xuất hiện, hệ thống nhảy vào hàm assert_failed. Trong hàm void assert_failed(uint8_t* file, uint32_t line), chúng ta được cung cấp 2 thông tin, đó là:
- uint8_t* file : file xuất hiện lỗi, ở đây là một con trỏ ký tự, trỏ đến xâu đường dẫn của tệp chứa lỗi
Ví dụ "D:\PROJECT\Drivers\src\ADC1.c"
- uint32_t line :dòng xuất hiện lỗi
Ta sử dụng 2 biến này để báo thông báo lỗi thông qua UART, UART, I2C, SPI, LCD,..
Ví dụ, thứ ta hay dùng nhất là LCD ta sẽ làm như sau:
Mã:
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
    LCD_Clear();//xóa LCD
    LCD_Puts((char*)file);//đưa ra LCD xâu có địa chỉ file
    LCD_Putn((uint16_t)line);//đưa ra số nguyên 2 byte
    while(1);//lặp vô hạn
  }
#endif
Nếu chương trình có lỗi vượt quá miền khả dụng của tham số LCD sẽ đưa ra đường dẫn của file và dòng xuất hiện lỗi. Dĩ nhiên là LCD của ta phải đủ lớn để chứa những thông tin đó, nếu không ta có thể sử dụng bằng cách thông báo qua UART,..
Trong trường hợp các bạn thấy bài viết của mình khó hiểu hoặc chức năng này không cần thiết, các bạn có thể vẫn làm theo cách bây lâu nay các bạn vẫn dùng là copy-paste đoạn mã truyền thống vào. Tuy nhiên, mình có cách nhanh hơn là thêm hai dấu gạch chéo trước dòng này trong file stm8s_conf.h (dòng thứ 90 nếu bạn dùng phiên bản v2.2.0 của thư viện ST)
Mã:
//#define USE_FULL_ASSERT    (1)
Nếu sử dụng cách này chúng ta sẽ tiết kiệm được một hoặc nhiều kB bộ nhớ cho em stm8 nhỏ xinh cute đấyfb:3
 
Sửa lần cuối:

Quảng cáo Google