Проблема заключается в неправильном понимании того, что делают охранники.Включающие охранники не позволяют компилятору снова видеть тот же контент в том же модуле перевода (для того же файла .cpp).Они не не позволяют отдельным блокам перевода видеть один и тот же код.
В вашем заголовочном файле вы определяете (не просто объявляете) переменные.Поэтому каждая единица перевода, которая включает в себя заголовок, создает свою собственную копию этих переменных.
Правильный способ сделать это - определить переменные в файле .cpp и объявить их только в заголовке (защитники включения должныв любом случае, чтобы предотвратить многократное включение в одну и ту же единицу перевода).
То есть в вашем файле sample.h добавьте к переменным префикс extern
и удалите инициализатор (поэтому они только объявлены,определены), и определите их в соответствующем файле .cpp (в котором также определены функции), поместив туда точные определения из вашего заголовка.
В несвязанной заметке вы должны поместить #include "mbed.h"
в sample.h внутри включаемых защит, потому что некоторые компиляторы оптимизируют скорость компиляции для таких защит, и эта оптимизация не работает, если есть материал вне защитных включений.Обратите внимание, что это на самом деле не проблема правильности (при условии, что mbed.h также должным образом защищен включаемыми защитниками), а проблема производительности компиляции.