У меня есть заголовочный файл ArduinoCanUtils.h и исходный файл ArduinoCanUtils.cpp, организованные в следующем дереве каталогов:
Documents
|---Arduino
| |---libraries
| |--- autowp-mcp2515
| | |--- other library files
| |
| |--- ArduinoCanUtils
| |--- ArduinoCanUtils.h
|--- ArduinoCanUtils.cpp
Эти файлы составляют библиотеку ArduinoCanUtils, которую я пытаюсь создать. Содержание ArduinoCanUtils.h следующее:
#ifndef ArduinoCanUtils_h
#define ArduinoCanUtils_h
#include <Arduino.h>
#include <stdint.h>
#include <mcp2515.h>
class ArduinoCanUtils
{
public:
ArduinoCanUtils();
uint32_t createCanMsgCanId(uint8_t priorityLevel, uint8_t activityCode, uint8_t destinationAddress, uint8_t originAddress);
uint8_t getPriorityLevelFromCanMsgCanId(uint32_t canId);
uint8_t getActivityCodeFromCanMsgCanId(uint32_t canId);
uint8_t getDestinationAddressFromCanMsgCanId(uint32_t canId);
uint8_t getOriginAddressFromCanMsgCanId(uint32_t canId);
void setAllCanMsgDataToZero(struct can_frame &canMsg);
};
#endif
А вот содержание ArduinoCanUtils.cpp следующее:
#include <Arduino.h>
#include <stdint.h>
#include <mcp2515.h>
#include "ArduinoCanUtils.h"
ArduinoCanUtils::ArduinoCanUtils(){}
uint32_t ArduinoCanUtils::createCanMsgCanId(uint8_t priorityLevel, uint8_t activityCode, uint8_t destinationAddress, uint8_t originAddress)
{
uint32_t canId = 0;
canId = canId | originAddress;
canId = canId | destinationAddress << 8;
canId = canId | ((uint32_t) activityCode) << 16;
for (int i = 0; i <= 2; i++){bitWrite(canId, 26 + i, bitRead(priorityLevel, i));}
bitWrite(canId, 31, 1);
return canId;
}
uint8_t ArduinoCanUtils::getPriorityLevelFromCanMsgCanId(uint32_t canId){
uint8_t priorityLevel = 0;
for (int i = 0; i <= 2; i++){bitWrite(priorityLevel, i, bitRead(canId, 26 + i));}
return priorityLevel;
}
uint8_t ArduinoCanUtils::getActivityCodeFromCanMsgCanId(uint32_t canId){
uint8_t activityCode = 0;
for (int i = 0; i <= 7; i++){bitWrite(activityCode, i, bitRead(canId, 16 + i));}
return activityCode;
}
uint8_t ArduinoCanUtils::getDestinationAddressFromCanMsgCanId(uint32_t canId){
uint8_t destinationAddress = 0;
for (int i = 0; i <= 7; i++){bitWrite(destinationAddress, i, bitRead(canId, 8 + i));}
return destinationAddress;
}
uint8_t ArduinoCanUtils::getOriginAddressFromCanMsgCanId(uint32_t canId){
uint8_t originAddress = 0;
for (int i = 0; i <= 7; i++){bitWrite(originAddress, i, bitRead(canId, i));}
return originAddress;
}
void ArduinoCanUtils::setAllCanMsgDataToZero(struct can_frame &canMsg){
for (int i = 0; i <= 7; i++){canMsg.data[i] = 0;}
}
Как видите, функция setAllCanMsgDataToZero требует тип struct can_frame в качестве аргумента. Этот тип определен в сторонней библиотеке autowp-mcp2515 (ссылка: https://github.com/autowp/arduino-mcp2515.git), но когда я пытаюсь использовать эту функцию в следующем тестовом скрипте :
#include <mcp2515.h>
#include <ArduinoCanUtils.h>
MCP2515 mcp2515Global(10);
struct can_frame canMsg = {.can_id = 0, .can_dlc = 8, .data = {0,0,0,0,0,0,0,0}};
ArduinoCanUtils canUtils;
void setup() {
// put your setup code here, to run once:
uint32_t a = canUtils.createCanMsgCanId(1, 1, 2, 1);
uint8_t b = canUtils.getActivityCodeFromCanMsgCanId(a);
canUtils.setAllCanMsgDataToZero(&canMsg);
}
void loop() {
// put your main code here, to run repeatedly:
}
После компиляции я получаю следующий журнал ошибок (см. изображение):
Интересно, что все остальные функции из моей библиотеки работают нормально, вот только с этой функцией возникают проблемы.
Я обязательно включил все необходимые зависимости. Кроме того, другие функции, кроме setAllCanMsgDataToZero, похоже, работают нормально. Я проверил, что правильно объявляю структуру can_fame, но не знаю, почему она продолжает выдавать эту ошибку. помощь будет очень признательна. Я впервые пишу библиотеку для Arduino, и я попробовал поискать в Интернете, но не нашел никакой помощи. Я надеюсь, что вы можете мне помочь.
«Я пытался поискать в Интернете, но не нашел никакой помощи». Существуют такие руководства, как Написание библиотеки для Arduino и Руководство по стилю библиотеки Arduino.
Кстати, такие вещи, как for (int i = 0; i <= 7; i++){canMsg.data[i] = 0;}, можно выполнить с помощью memset(canMsg.data,0);, а большинство методов, таких как вся функция getPriorityLevelFromCanMsgCanId(uint32_t canId), можно выполнить с помощью однострочника, как (canId & 0x1c000000) > 26; (т. е. шаблон (canId & bit_mask) >> bit_position). Прочтите Bit Math или просто возьмите одну из книг по C++ и прочитайте ее.
-хечуг, спасибо за помощь!. Постараюсь ответить на каждый ваш комментарий в хронологическом порядке: 1) Вы были правы. Я переместил все строки, в которых вызываю методы CanUtils, внутри void setup(), и теперь появилась новая ошибка: «ошибка компиляции: нет соответствующей функции для вызова «ArduinoCanUtils::setAllCanMsgDataToZero(can_frame*)». Как я мог это решить? 2) Я действительно последовал примеру этой ссылки, но она не касается зависимостей. 3) Спасибо, приму во внимание, хотя в моем случае я предпочитаю читабельность и интуитивность производительности, так как я нуб.
В исходном дизайне параметр функции передается по ссылке с помощью &canMsg, а теперь вы передаете параметр по указателю *canMsg.
@hcheung, еще раз спасибо. Я посмотрел ссылку, которую вы разместили, и теперь вижу ошибку. Я не был так хорошо знаком с «передачей по ссылке», как думал. Мне следует использовать canUtils.setAllCanMsgDataToZero(canMsg) вместо canUtils.setAllCanMsgDataToZero(&canMsg), так как во втором случае я передаю указатель, а функция просто ожидает ссылку. Спасибо. Отмечаю вопрос как отвеченный.





Я не был так хорошо знаком с «передачей по ссылке», как думал. Мне следует использовать canUtils.setAllCanMsgDataToZero(canMsg) вместо canUtils.setAllCanMsgDataToZero(&canMsg), так как во втором случае я передаю указатель, а функция просто ожидает ссылку.
Оказывается, это вовсе не проблема зависимости.
C++ 101: глобальное пространство предназначено для объявления переменных и создания экземпляра класса, а не для вызова метода класса для выполнения кода. Поэтому переместите это выполнение в функцию (т. е. в вашу настройку() или цикл()).