f362dc_featuresdemo.c
来自「8051试验程序 基础教材」· C语言 代码 · 共 754 行 · 第 1/2 页
C
754 行
//
//-----------------------------------------------------------------------------
void ADC0_Init (void)
{
unsigned char SFRPAGE_save = SFRPAGE; // Save the current SFRPAGE
SFRPAGE = CONFIG_PAGE; // Switch to the necessary SFRPAGE
ADC0CN = 0x02; // Disable ADC0
// Normal Track Mode
// Enable conversion on Timer2 overflow
AMX0P = 0x06; // P1.6 is the positive input
AMX0N = 0x1F; // GND is the negative input
ADC0CF = (SYSCLK/ADC_CLOCK) << 3; // ADC conversion clock <= 3MHz
ADC0CF &= ~0x04; // Make ADC0 right-justified
EIE1 |= 0x08; // Enable ADC0 conversion-complete
// interrupts
REF0CN = 0x0A; // VREF = VDD, bias generator is on.
ADC0CN_bit.AD0EN = 1; // Enable ADC0
SFRPAGE = SFRPAGE_save; // Restore the SFRPAGE
}
//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure the UART1 using Timer1, for <baudrate> and 8-N-1.
//
//-----------------------------------------------------------------------------
void UART0_Init (void)
{
unsigned char SFRPAGE_save = SFRPAGE; // Save the current SFRPAGE
SFRPAGE = CONFIG_PAGE; // Switch to the necessary SFRPAGE
SCON0 = 0x10; // SCON0: 8-bit variable bit rate
// level of STOP bit is ignored
// RX enabled
// ninth bits are zeros
// clear RI0 and TI0 bits
if (SYSCLK/BAUDRATE/2/256 < 1) {
TH1 = (0xFF-(SYSCLK/BAUDRATE/2))+1;
CKCON &= ~0x0B; // T1M = 1; SCA1:0 = xx
CKCON |= 0x08;
} else if (SYSCLK/BAUDRATE/2/256 < 4) {
TH1 = (0xFF-(SYSCLK/BAUDRATE/2/4))+1;
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 01
CKCON |= 0x09;
} else if (SYSCLK/BAUDRATE/2/256 < 12) {
TH1 = (0xFF-(SYSCLK/BAUDRATE/2/12))+1;
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 00
} else {
TH1 = -(SYSCLK/BAUDRATE/2/48);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 10
CKCON |= 0x02;
}
TL1 = TH1; // Init Timer1
TMOD &= ~0xf0; // TMOD: timer 1 in 8-bit autoreload
TMOD |= 0x20;
TCON_bit.TR1 = 1; // START Timer1
SCON0_bit.TI0 = 1; // Indicate TX0 ready
SFRPAGE = SFRPAGE_save; // Restore the SFRPAGE
}
//-----------------------------------------------------------------------------
// PCA0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure Module0 to 8-bit PWM. The duty cycle is initially set to 50%. The
// duty cycle will actually be determined by the value of the potentiometer.
//
// The PCA counter isn't started until the user switches to PWM mode.
//
//-----------------------------------------------------------------------------
void PCA0_Init (void)
{
unsigned char SFRPAGE_save = SFRPAGE; // Save the current SFRPAGE
SFRPAGE = CONFIG_PAGE; // Switch to the necessary SFRPAGE
// Configure PCA time base; overflow interrupt disabled
PCA0CN = 0x00; // Stop counter; clear all flags
PCA0MD = 0x08; // Use SYSCLK as time base
PCA0CPM0 = 0x42; // Module 0 = 8-bit PWM mode
// Configure initial PWM duty cycle = 50%
PCA0CPH0 = 256 - (256 * 0.5);
SFRPAGE = SFRPAGE_save; // Restore the SFRPAGE
}
//-----------------------------------------------------------------------------
// INT0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure /INT0 (P0.6) to be a level-sensitive interrupt pin.
// Starts active-low, but the INT0 ISR will switch this back and forth.
//
//-----------------------------------------------------------------------------
void INT0_Init (void)
{
unsigned char SFRPAGE_save = SFRPAGE; // Save the current SFRPAGE
SFRPAGE = CONFIG_PAGE; // Switch to the necessary SFRPAGE
IT01CF = 0x06; // Configure /INT0 to P0.6
// Active High
TCON_bit.IT0 = 0; // /INT0 is level sensitive
IE_bit.EX0 = 1; // Enable /INT0 interrupts
SFRPAGE = SFRPAGE_save; // Restore the SFRPAGE
}
//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// INT0_ISR
//-----------------------------------------------------------------------------
//
// INT0_ISR is triggered upon a level transition on the /INT0 pin.
// If /INT0 is logic high, the firmware switches to a state that blinks the LED
// If /INT0 is logic low, the fimware applies PWM wave to the LED to control
// the brightness.
//
//-----------------------------------------------------------------------------
#pragma vector = IE0_int
__interrupt void INT0_ISR (void)
{
char SFRPAGE_save = SFRPAGE;
if (IT01CF & 0x08) // Currently active-high
{
IT01CF &= ~0x08; // Switch to active-low
Blink_State = TIMER_MODE; // State is now Timer mode
update = 1;
// Switch to Timer Mode
PCA0CN_bit.CR = 0; // Stop PCA Counter
TMR3CN |= 0x04; // Start Timer3
SFRPAGE = CONFIG_PAGE;
XBR1 &= ~0x01; // Remove CEX0 from Crossbar
}
else
{
IT01CF |= 0x08; // Switch to active-high
Blink_State = PWM_MODE; // State is now PWM mode
update = 1;
// Switch To PWM Mode
TMR3CN &= ~0x04; // Stop Timer3
PCA0CN_bit.CR = 1; // Start PCA Counter
SFRPAGE = CONFIG_PAGE;
XBR1 |= 0x01; // Put CEX0 on Crossbar (P1.3)
}
SFRPAGE = SFRPAGE_save;
}
//-----------------------------------------------------------------------------
// TIMER0_ISR
//-----------------------------------------------------------------------------
//
// This ISR is triggered upon a Timer0 overflow. It is used to update the
// UART with the status of the LED.
//
//-----------------------------------------------------------------------------
#pragma vector = TF0_int
__interrupt void TIMER0_ISR (void)
{
static int overflows = 0;
// Timer0 is used to schedule the number of times per second the status is
// printed to the UART. Since Timer0 and Timer1 share a SYSCLK prescaler,
// it is easier to use the prescaler only for Timer1 (UART) and run
// Timer0 from SYSCLK. Running Timer0 from SYSCLK requires keeping track
// of the number of Timer0 overflows to schedule a reasonable UART update
// rate. Updating on every Timer0 overflow would print too fast.
// The benefit is that there is more flexibility in scheduling the update
// rate as it is no longer any dependent on the fixed UART prescaler.
overflows++;
if (overflows == OVERFLOWS_NEEDED) // Time to print
{
if ((Blink_State == TIMER_MODE) & update) // Timer mode
{
putchar ('\f'); // Clear screen
Print_String ("LED Blink Rate: ");
// Add a hundreds digit if <MAX_BLINK_RATE> requires one
putchar ((Blink_Rate / 10) + 0x30); // Tens digit
putchar ((Blink_Rate % 10) + 0x30); // Ones digit
Print_String (" Hz\n");
update = 0;
}
else if ((Blink_State == PWM_MODE) & update) // PWM mode
{
putchar ('\f'); // Clear screen
Print_String ("LED PWM Duty Cycle: ");
putchar ((PWM_Duty_Cycle / 100) + 0x30); // Hundreds digit
putchar (((PWM_Duty_Cycle / 10) % 10) + 0x30); // Tens digit
putchar ((PWM_Duty_Cycle % 10) + 0x30); // Ones digit
Print_String (" %\n");
update = 0;
}
overflows = 0; // Reset the count
}
}
//-----------------------------------------------------------------------------
// ADC0_ISR
//-----------------------------------------------------------------------------
//
// ADC0_ISR is triggerered upon the completion of an ADC conversion. The ISR
// calculates the Blink_Rate or PWM_Duty_Cycle based on the voltage
// across the potentiometer.
//
// Blink mode:
// A full-scale reading will configure the Timer to blink the LED at
// <MAX_BLINK_RATE>
// A zero reading will configure the Timer the LED to blink at <MIN_BLINK_RATE>
//
// PWM mode:
// A full scale value will configure the PCA to use a duty cycle of 100%
// A zero reading will configure the PCA to use a duty cycle of 0%
//
//-----------------------------------------------------------------------------
#pragma vector = AD0INT_int
__interrupt void ADC0_ISR (void)
{
unsigned int ADC_result;
unsigned long reload_speed, percentage;
static int PWM_Duty_Cycle_Old = 0;
static int Blink_Rate_Old = 0;
// The ADC, PCA, and TIMER registers are available on all SFR pages, so there
// is no need to switch the SFR page before writing to these registers.
ADC0CN_bit.AD0INT = 0; // Clear conversion complete flag
ADC_result = ADC0;
if (Blink_State == TIMER_MODE)
{
if (ADC_result == 0x03FF) // Assume max reading indicates VDD
{ // and not (VDD - 1 LSB)
reload_speed = MAX_BLINK_RATE;
}
else
{
reload_speed = (long) (ADC_result * BLINK_DIFF);
reload_speed = reload_speed / ADC_COUNTS;
reload_speed += MIN_BLINK_RATE;
}
Blink_Rate = reload_speed; // Set global variable
if (Blink_Rate != Blink_Rate_Old) {
update = 1; }
Blink_Rate_Old = Blink_Rate;
TMR3RL = - ((unsigned int) (SYSCLK / 12 / reload_speed));
}
else
{
if (ADC_result == 0x03FF) // Assume max reading indicates VDD
{ // and not (VDD - 1 LSB)
percentage = 255;
PWM_Duty_Cycle = 100;
}
else
{
percentage = (long) ADC_result * (long) 256;
percentage = (long) percentage / (long) ADC_COUNTS;
PWM_Duty_Cycle = (int) ( ((long)ADC_result * (long)100) / (long)ADC_COUNTS );
}
if (PWM_Duty_Cycle != PWM_Duty_Cycle_Old) {
update = 1; }
PWM_Duty_Cycle_Old = PWM_Duty_Cycle;
// Set new PCA0 Module0 PWM duty cycle
PCA0CPH0 = (char) percentage;
}
}
//-----------------------------------------------------------------------------
// TIMER3_ISR
//-----------------------------------------------------------------------------
//
// This ISR is triggered upon a Timer3 overflow. The ISR simply toggles
// the state of the LED and keeps track of the number of times the LED blinks.
//
//-----------------------------------------------------------------------------
#pragma vector = ET3_int
__interrupt void TIMER3_ISR (void)
{
// The TMR3CN and Port registers are available on all SFR pages, so there
// is no need to switch the SFR page before writing to these registers.
TMR3CN &= ~0x80; // Clear Timer3 Flags
LED = !LED;
Num_LED_Flashes++;
}
//-----------------------------------------------------------------------------
// Support Functions
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Print_String
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters :
// 1) char pstring[] - null terminated character string
//
// Prints the strings stored in pstring to the UART.
//
//-----------------------------------------------------------------------------
void Print_String (char pstring[])
{
// The SBUF0 register is available on all SFR pages, so there is no
// need to switch the SFR page before calling putchar().
unsigned char i = 0;
while (pstring[i])
{
putchar(pstring[i++]);
}
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?