




Если нет библиотечной функции, определенной библиотекой времени выполнения поставщика компилятора (если такая библиотека даже существует в мире микроконтроллеров ... но должна), тогда нет. Сам по себе C определенно не поможет вам, выполнение «сброса» - это слишком специфическая для платформы проблема, чтобы C мог ее решить.
Я использую компилятор ccsinfo.com, у которого есть аналогичный вызов API для сброса PIC, но я думаю, что решение компилятора будет делать правильные вещи.
Есть FAQ здесь.
В: Как мне сбросить микроконтроллер?
One way is to reset all variables to their defaults, as listed in the PIC manual. Then, use assembly language to jump to location 0x0000 in the micro.
#asm ljmp 0x0000
#endasm
This is quite safe to use, even when called within interrupts or procedures. The PIC 16x series micros have 8 stack levels. Each time a procedure is called, one stack level is used up for the return address. It is a circular buffer, so even if the micro is 7 procedure levels deep and in an interrupt when a reset is called, this is the new start of the stack buffer, and the micro will continue as per normal.
Another way is to set watchdog the timer when the chip is programmed, and use CLRWDT() instructions all through the code. When you want the micro to reset, stop clearing the watchdog bit and the micro will reset after around 18ms to 2 seconds depending on the prescaler.
Переход к 0x0000 не приведет к сбросу каких-либо аппаратных периферийных устройств. Я бы использовал сторожевой таймер или инструкцию по сборке сброса.
Я знаю, что это очень старый вопрос, но я наткнулся на него с аналогичной проблемой. Согласно странице Microchip на YouTube связь, к PIC добавлены некоторые новые улучшенные инструкции. Одна из них - инструкция по сбросу. У меня это еще не работает, и я не могу найти много информации о нем, но похоже, что способ есть.
@DanTwining: спасибо за обновление. Для Microchip было бы разумно добавить это усовершенствование через 3 года, которые прошли :)
Переход к 0x0000 не приведет к сбросу стека, сделайте это достаточное количество раз из функции, и вы получите переполнение стека!
@Cobusve: этому ответу 7 лет. Было бы более конструктивно предложить изменения, которые обновят его до современного ответа, чтобы помочь людям, которые наткнулись на этот вопрос. Здесь я превратил его в «вики сообщества», чтобы упростить обновление.
В компиляторы обычно встроена собственная функция reset (), но она выполняет именно то, что делает ваша функция, а фактическое имя может варьироваться от компилятора к компилятору.
Вы уже делаете это наилучшим образом.
Ваш ответ - лучший из известных мне способов. Ключ в том, что у вас есть инструкция по сборке внутри вызова функции, сама по себе. Компилятор не будет оптимизировать функцию, в которой есть встроенная сборка, поэтому, если вы включите встроенную инструкцию сброса в очень большую функцию, компилятор не будет оптимизировать какой-либо код в этой функции. Вы избежали этого, поместив Reset в отдельную функцию. Код в этой функции не будет оптимизирован, но кого это волнует, ведь это такая маленькая функция.
Поскольку Майк редактировал этот исходный вопрос 11 лет назад, кажется сомнительным, что исходный плакат нуждается в исчерпывающем ответе. Фактически, OP, кажется, спросил или ответил только на 2 темы, касающиеся микроконтроллеров, за последние 9 лет.
Учитывая все это, может быть полезно взглянуть на некоторые способы, которыми контроллер PIC18F может быть инициирован для начала выполнения из вектора сброса с кодом, который компилируется с Hi-Tech C или XC8, поскольку он не вызывается Microchip.
Этот код был протестирован с использованием MPLABX v5.25, XC8 v2.05 и контроллера PIC18F45K20.
/*
* File: main.c
* Author: dan1138
* Target: PIC18F45K20
* Compiler: XC8 v2.05
*
* PIC18F46K20
* +---------+ +---------+ +----------+ +----------+
* <> 1 : RC7/RX : -- 12 : NC : <> 23 : RA4 : -- 34 : NC :
* LED4 <> 2 : RD4 : -- 13 : NC : <> 24 : RA5 : 32.768KHz -> 35 : RC1/SOSI :
* LED5 <> 3 : RD5 : <> 14 : RB4 : <> 25 : RE0 : <> 36 : RC2 :
* LED6 <> 4 : RD6 : <> 15 : RB5/PGM : <> 26 : RE1 : <> 37 : RC3 :
* GND -> 5 : VSS : PGC <> 16 : RB6/PGC : <> 27 : RE2 : LED0 <> 38 : RD0 :
* 3v3 -> 6 : VDD : PGD <> 17 : RB7/PGD : 3v3 -> 28 : VDD : LED1 <> 39 : RD1 :
* SW1 <> 7 : RB0/INT : VPP -> 18 : RE3/VPP : GND -> 29 : VSS : LED2 <> 40 : RD2 :
* <> 8 : RB1 : POT <> 19 : RA0/AN0 : 4MHz -> 30 : RA7/OSC1 : LED3 <> 41 : RD3 :
* <> 9 : RB2 : <> 20 : RA1 : 4MHz <- 31 : RA6/OSC2 : <> 42 : RC4 :
* <> 10 : RB3 : <> 21 : RA2 : 32.767KHz <- 32 : RC0/SOSO : <> 43 : RC5 :
* LED7 <> 11 : RD7 : <> 22 : RA3 : -- 33 : NC : <> 44 : RC6/TX :
* +---------+ +---------+ +----------+ +----------+
* TQFP-44
*
*
* Created on December 21, 2019, 2:26 PM
*/
/* Target specific configuration words */
#pragma config FOSC = INTIO67, FCMEN = OFF
#pragma config IESO = OFF, PWRT = OFF, BOREN = SBORDIS, BORV = 18
#pragma config WDTEN = OFF, WDTPS = 32768, CCP2MX = PORTC, PBADEN = OFF
#pragma config LPT1OSC = ON, HFOFST = ON
#pragma config MCLRE = ON, STVREN = ON, LVP = OFF, XINST = OFF
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF
#pragma config CPB = OFF, CPD = OFF
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF
#pragma config WRTC = OFF, WRTB = OFF, WRTD = OFF
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF
#pragma config EBTRB = OFF
/* Target specific definitions for special function registers */
#include <xc.h>
/* Declare the system oscillator frequency setup by the code */
#define _XTAL_FREQ (4000000UL)
/* reset instruction */
void ResetMethod_1(void)
{
asm(" reset");
}
/* long jump to absolute address zero */
void ResetMethod_2(void)
{
INTCON = 0;
asm(" pop\n ljmp 0");
}
/* return to absolute address zero */
void ResetMethod_3(void)
{
INTCON = 0;
asm(" clrf TOSU\n clrf TOSH\n clrf TOSL\n");
}
/* provoke stackoverflow reset */
void ResetMethod_4(void)
{
INTCON = 0;
while (1)
{
asm(" push\n");
}
}
/* provoke stackunderflow reset */
void ResetMethod_5(void)
{
INTCON = 0;
STKPTR = 0;
}
/* clear the program counter */
void ResetMethod_6(void)
{
INTCON = 0;
asm(" clrf PCLATU\n clrf PCLATH\n clrf PCL\n");
}
void main(void)
{
INTCON = 0; /* Disable all interrupt sources */
PIE1 = 0;
PIE2 = 0;
INTCON3bits.INT1IE = 0;
INTCON3bits.INT2IE = 0;
OSCCON = 0x50; /* set internal oscillator to 4MHz */
OSCTUNEbits.TUN = 0; /* use factory calibration of internal oscillator */
ANSEL = 0;
ANSELH = 0;
if (!RCONbits.nPOR)
{
RCONbits.nPOR = 1;
LATD = 0;
}
TRISD = 0;
/*
* Application loop
*/
while(1)
{
__delay_ms(500);
if (LATDbits.LD0 == 0)
{
LATDbits.LD0 = 1;
ResetMethod_1();
}
if (LATDbits.LD1 == 0)
{
LATDbits.LD1 = 1;
ResetMethod_2();
}
if (LATDbits.LD2 == 0)
{
LATDbits.LD2 = 1;
ResetMethod_3();
}
if (LATDbits.LD3 == 0)
{
LATDbits.LD3 = 1;
ResetMethod_4();
}
if (LATDbits.LD4 == 0)
{
LATDbits.LD4 = 1;
ResetMethod_5();
}
if (LATDbits.LD5 == 0)
{
LATDbits.LD5 = 1;
ResetMethod_6();
}
}
}
может быть лучший способ сделать что-нибудь, чем вызов одной инструкции ASM? зачем вам сбросить весь контроллер? вы собираетесь сбросить все периферийные устройства? только что записано во флеш-память PGM? (это единственный хороший повод сделать это)