Ссылка the C8051F330 datasheet, Таблица 15.1.
Каждый источник прерываний (сброс, переполнение таймера 0, SMB0 и т. Д.) Имеет адрес вектора прерываний с жестко запрограммированным кодом. Когда прерывание утверждается, микрогенератор генерирует команду LCALL
этому адресу вектора. SMB0 равен 0x003B, например, переполнение таймера 0 - 0x000B. Когда вы кодируете обработчик прерываний (ключевое слово в Keil, см. this question для других примеров), ваш компоновщик обычно ставит какую-то инструкцию JMP
по векторному адресу, чтобы добраться до вашего обработчика.
Если вы пренебрегаете записью обработчика для включенного прерывания, микро будет по-прежнему векторным для этого адреса. То, что происходит тогда, зависит от того, что компоновщик помещает где-то в кодовом пространстве. Я нахожу, что небольшие функции, как правило, заполняются между векторными адресами, особенно если вы не используете много прерываний и есть несколько смежных векторных адресов, которые не используются. Вы можете узнать, просмотрев пространство кода в 0x003B (векторный адрес SMB0) в дизассемблере.
Если вы случайно попали в середину некоторой такой функции, расположенной в неправильном месте в нужное время, вы получите какие-либо побочные эффекты от части выполняемой функции, а затем RET
в конце функция вернет вас туда, где вы были до прерывания. Кроме того, поскольку вы не прошли через RETI
, прерывание не очищается. Любые будущие прерывания с таким же или более низким приоритетом будут заблокированы, так как микро думает, что вы все еще обслуживаете прерывание SMB0.
Вы предположили, что NOP
может заменить нереализованных обработчиков, но это невозможно сделать, поскольку ваша инструментальная цепочка не знает, какие прерывания включены во время компиляции. Если вы не пишете обработчик и не находите его на определенном векторном адресе, он предполагает, что эта часть пространства кода является честной игрой и добавит что-то еще.