unsigned char num;
//
// Timer interrupt service routine
//
void interrupt() {
HID_InterruptProc(); // Keep alive
TMR0L = 100; // Re-load TMR0L
INTCON.TMR0IF = 0; // Re-enable TMR0 interrupts
}
//
// Start of MAIN program
//
void main() {
ADCON1 = 0xFF; // Set PORTB to digital I/O
TRISB = 0; // Set PORTB to outputs
PORTB = 0; // Clear all outputs
//
// Set interrupt registers to power-on defaults
// Disable all interrupts
//
INTCON=0;
INTCON2=0xF5;
INTCON3=0xC0;
RCON.IPEN=0;
PIE1=0;
PIE2=0;
PIR1=0;
PIR2=0;
//
// Configure TIMER 0 for 3.3ms interrupts. Set prescaler to 256
// and load TMR0L to 100 so that the time interval for timer
// interrupts at 48MHz is 256*(256-100)*0.083 = 3.3ms
//
// The timer is in 8-bit mode by default
//
T0CON = 0x47; // Prescaler = 256
TMR0L = 100; // Timer count is 256-156 = 100
INTCON.TMR0IE = 1; // Enable T0IE
T0CON.TMR0ON = 1; // Turn Timer 0 ON
INTCON = 0xE0; // Enable interrupts
//
// Enable USB port
//
Hid_Enable(&Read_buffer, &Write_buffer);
Delay_ms(1000);
Delay_ms(1000);
//
// Read from the USB port. Number of bytes read is in num
//
for(;;) // do forever
{
num=0;
while(num != 4) // Get 4 characters
{
num = Hid_Read();
}
if (Read_buffer[0] == 'P' && Read_buffer[1] == '=' &&
Read_buffer[3] == 'T') {
PORTB = Read_buffer[2];
}
}
Hid_Disable();
}
Figure 8.22: Microcontroller program with USB code
Inside the main program PORTB is defined as digital I/O and TRISB is cleared to 0 so all PORTB pins are outputs. All the interrupt registers are then set to their power-on-reset values for safety. The timer interrupts are then set up. The timer is operated in 8-bit mode with a prescaler of 256. Although the crystal clock frequency is 8MHZ, the CPU is operated with a 48MHz clock, as described later. Selecting a timer value of TMR0L . 100 with a 48MHz clock (CPU clock period of 0.083μs) gives timer interrupt intervals of:
(256 – 100) * 256 * 0.083μs
or, about 3.3ms. Thus, the keep-alive messages are sent every 3.3ms.
The USB port is then enabled by calling function Hid_Enable. The program then enters an indefinite loop and reads data from the USB port with Hid_Read. When 4 bytes are received at the correct format (i.e., byte 0=“P,” byte 1=“.”, and byte 3=“T”) then the data byte is read from byte 2 and sent to PORTB of the microcontroller.
It is important to note that when data is received using the Hid_Read function, the function returns the number of bytes received. In addition, the first byte received is the first actual data byte and not the report ID.
The USB module of the PIC18F4550 microcontroller requires a 48MHz clock. In addition, the microcontroller CPU requires a clock that can range from 0 to 48MHz. In this project the CPU clock is set to be 48MHz.
There are several ways to provide the required clock pulses.
Figure 8.23 shows part of the PIC18F4550 clock circuit. The circuit consists of a 1:1–1:12 PLL prescaler and multiplexer, a 4:96MHz PLL, a 1:2–1:6 PLL postscaler, and a 1:1–1:4 oscillator postscaler. Assuming the crystal frequency is 8MHz and we want to operate the microcontroller with a 48MHz clock, and also remembering that a 48MHz clock is required for the USB module, we should make the following choices in the Edit Project option of the mikroC IDE:
• Set _PLL_DIV2_1L so the 8MHz clock is divided by 2 to produce 4MHZ at the output of the PLL prescaler multiplexer. The output of the 4:96MHZ PLL is now 96MHz. This is further divided by 2 to give 48MHz at the input of multiplexer USBDIV.
• Check _USBDIV_2_1L to provide a 48MHz clock to USB module and to select ÷2 for the PLL postscaler.
• Check CPUDIV_OSC1_PLL2_1L to select PLL as the clock source.
• Check _FOSC_HSPLL_HS_1H to select a 48MHz clock for the CPU.
• Set the CPU clock to 48MHz in mikroC IDE (using Edit Project).
Figure 8.23: PIC18F4550 microcontroller clock
The clock bits selected for the 48MHz USB operation with a 48MHz CPU clock are shown in Figure 8.24.
Figure 8.24: Selecting clock bits for USB operation
Setting other configuration bits in addition to the clock bits is recommended.
The following list gives all the bits that should be set in the Edit Project option of the IDE (most of these settings are the power-on-reset values of the bits):
PLLDIV_2_1L
CPUDIV_OSC1_PLL2_1L
USBDIV_2_1L
FOSC_HSPLL_HS_1H
FCMEM_OFF_1H
IESO_OFF_1H
PWRT_ON_2L
BOR_ON_2L
BORV_43_2L
VREGEN_ON_2L
WDT_OFF_2H
WDTPS_256_2H
MCLRE_ON_3H
LPT1OSC_OFF_3H
PBADEN_OFF_3H
CCP2MX_ON_3H
STVREN_ON_4L
LVP_OFF_4L
ICPRT_OFF_4L
XINST_OFF_4L
DEBUG_OFF_4L
Testing the Project
Testing the project is relatively easy. The steps are:
• Construct the hardware
• Load the program (Figure 8.22) into the PIC18F4550 microcontroller
• Copy or run the PC-based Visual Basic program
When the microcontroller is connected to one of the USB ports of the PC, a message should be visible at the bottom right-hand corner of the screen similar to the one in Figure 8.25. This message shows that the new USB HID device has been plugged in and is recognized by the PC.
Figure 8.25: USB connection message
In addition, the device manager display should show an HID-compliant device and a USB human interface device as in Figure 8.26. The properties of these drivers can be displayed to make sure the VIP is 0x1234 and the PID is 1.