This project introduces you to the synthesis and analysis tools for producing microprocessor C code using the MPLAB® X integrated development environment (IDE) on the chipKIT™ Pro MX7 processor board.
The purpose of this project is to familiarize you with the methods of reading from and writing to the input and output (I/O) pins of the PIC™32 microcontroller.
The purpose of this project is to investigate methods of creating software time delays to pace processor operations.
The purpose of this project is to investigate the application of software-based state machines to controlling the speed, direction of rotation, and operational mode of stepper motors.
The purpose of this project is to understand the operation of PIC™32 timers so that they can be used to implement a synchronized multi-rate periodic control system by polling the timer interrupt flag.
Explore detecting events using interrupts or by using preemption that implements a nested interrupt management scheme.
Investigate concepts involving parallel communications and handshaking.
Learn about asynchronous communications and communicate with a microcontroller using a terminal emulation program to implement a point to point serial link between the chipKIT™ PRO MX7 and a PC.
Investigate concepts involving synchronous communications using a basic master-slave multi-drop network communications and use the I2C protocol to communicate with the 24LC256 I2C™ CMOS Serial EEPROM.
Investigate synchronous communications with the SPI master-slave serial bus
Generate a proportional output using the output compare resource on the PIC®32MX processor to implement digital-to-analog conversion with pulse width modulation (PWM), thus controlling the speed of a DC motor.
Use the PIC™ 32 input capture to measure frequency to determine the speed of a DC motor.
The purpose of this project is to learn about asynchronous communications and how to communicate with a microcontroller using a terminal emulation program to implement a point-to point-serial link between the chipKIT™Pro MX7 and a PC. This project models a system that has both local and remote control.
Qty | Description | |
---|---|---|
1 | chipKIT Pro MX7 processor board with USB cable | ![]() |
1 | Microchip MPLAB® X IDE | ![]() |
1 | PmodCLP™ Parallel LCD Module | ![]() |
1 | PmodRS232™ | ![]() |
1 | Digilent UART Pmod crossover cable | ![]() |
Asynchronous communications is a serial data protocol that has been in use for many years. Normally eight bits of data are transmitted at a time. There are other less commonly used modes that can send 5, 6, or 7 bits of data. Each byte of data is framed by a start bit and a stop bit. A symbol is defined as a start, data, parity, or stop bit. It is common to define communications speed as bits per second. The bit rate is defined as the inverse of the period of a unit symbol. Although the common standard bit rates are 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, and 115200, communications are possible at any rate provided that the sender and receiver use the same rate. For most asynchronous communications, the term “baud” is commonly used interchangeably with the term “bit rate.”
As shown in Fig. 1, the idle state of the transmit signal is a logic one or a high voltage level. A start bit is signified by a high to low transition and remains low for one symbol time. The start bit is followed by eight data bits. A logic zero is sent when the signal is a low voltage level for one symbol time. Similarly, a logic one is sent when the signal is a high voltage level for one symbol time. After the transmitting of the data (least significant bit first) there may be an optional parity bit. The parity bit is used for error detection and can be set for even parity or odd parity. For even parity, the parity bit is set high if the number of ones in the preceding eight data bits are odd, thus making the total number of 1's in the data plus parity bit even. Conversely, for odd parity, the parity bit is set high if the number of ones in the 8 data is even. The data byte is terminated with one or more successive stop bits. Stop bits are always a logic 1 or high voltage level. If the signal remains high for longer than one symbol period, the stop bit can be thought of as the stop or idle period and the communications signal may remain in the idle condition an arbitrarily long period of time.
The receiving device unit must use the same bit rate as the sending unit. In the process of receiving serial communications, a processor may generate up to three error flags. A parity error is generated if the parity bit is at the incorrect voltage level. The second type of error is a framing error that is generated if a low voltage level is received in the stop bit position. Thirdly, an overrun error is generated if a software instruction does not read the data byte from the receive buffer before the next byte of data is completely received resulting in the new data byte overwriting the previous data byte.
Each new start bit synchronizes the sampling of the receiving unit. Generally, the receiver recovers the transmission using a clock that is an even multiple of the bit rate. When the receiving unit detects the falling edge of the START bit, it waits one half the symbol period and samples the receive data line. This is illustrated by the processor sample points in Fig. 1. If the logic state of the line is zero, then it is recognized as a valid start condition. The receiver then waits full periods to sample the receive data line until all data bits plus any parity bit plus the stop bit have been received. If a stop bit is not received, a framing error is generated.
Just as with parallel communications, there are three modes of serial communications: full-duplex, half-duplex, and simplex. Full-duplex describes the operation when a device can simultaneously send and receive data. Half-duplex operation allows both sending and receiving but not simultaneously. Simplex operations are where the device can only send or receive data.
The actual data rate is defined as the number of data bits per unit time. Data efficiency is defined as the number of data bits divided by the total number of bits. The efficiency of asynchronous serial communications is at best 80% because there are always two extra data bits (start and stop bit) sent for each 8 data bits. If parity is used, the efficiency drops to 73% because 11 bits are needed to communicate 8 bits of data.
A universal asynchronous receiver/transmitter, abbreviated UART, is a type of “asynchronous receiver/transmitter.” A UART is an electronic device or microprocessor peripheral that translates data between parallel and serial forms. UARTs are usually capable of full-duplex communications.
UARTs are typically used in conjunction with asynchronous communication standards, such as IrDa, SDI-12, EIA, RS-232, RS-422, or RS-485. RS-232 is a commonly used standard that originated in the early 1960s. The standard defines the connector pins, the data rates, and voltage levels. The RS-232 standard requires a signal driver that both inverts the polarity and expands the voltage levels representing logic ones and zeros. This signal driver IC is on the PmodRS232. As shown in Fig. 2, the RS-232 data is bi-polar: +3 TO +12 volts indicate an “ON” or 0-state (“SPACE”) condition while a -3 to -12 volts indicates an “OFF” 1-state (“MARK”) condition. (Note the inversion of the logic on the output of the driver IC.) Modern computer equipment ignore the negative level and accepts a zero voltage level as the “OFF” state. For many present day UARTs, the “ON” state may be achieved with lesser positive potential. This means circuits powered by 5 VDC are capable of driving RS-232 circuits directly; however, the overall physical range that the RS-232 signal may be transmitted / received may be dramatically reduced.
Since the RS-232 transmit driver will actively drive the communications line both to high and low voltage levels, it is generally not used in a communications network that consists of many transmitters and receivers sharing a common electrical line. It can, however, be used in a simplex operation where one transmitter communicates with many receivers. Although the PIC32 can host up to six asynchronous serial ports, the chipKIT Pro MX7 can host up to two—UART1 and UART2.
PCs and other computer systems that have capability to communicate using the RS-232 standard typically use a DB-9 connector to interface with the communications wires. The pin number assignments for a female DB 9 connector are shown in Fig. 3. The functionality of the DB 9 connector pins are made on the basis of the connector attaching to data terminal equipment (DTE) or data communications equipment (DCE). The DTE refers to the end device that uses or generates the information. It is the connector on the back of the PC. The DCE refers to equipment that transmits or receives analog or digital signals over the connecting media. It is sometimes called the modem (modulator / demodulator). The connecting media can be wire, fiber optic cable, water (in the case of acoustic modems), or space for cases such as radio frequency (RF) and infrared (IR) modems. Figure 4 shows the pins and functionality for a DTE to DCE connection. In this project, we will use only the Rx (DTE pin 2), Tx (DTE pin 3), and the common signal (pin 5). The pin assignment for PmodRS232 is that of a DCE device even though the PIC32 and the PC both generate and use the the information.
A null modem is sometimes referred to as a cross-over cable at allows two devices that have the same DTE or DCE connectors to communicate with each other directly. The connection diagram for a NULL modem shown in Fig. 5 illustrates the cross over connections for the Tx and Rx signals as well as the optional handshaking signals.
The data that is communicated over a serial communications connection is not constrained to ASCII text. However, using only ASCII text frequently simplifies the development of communications systems. The interface with the LCD used in Project 6 is an example of parallel communication using ASCII text strings. In C, a text string is an array of characters that uses the data value of zero to indicate the end of the string regardless of the array size (provided the string length is less than the array size). The character data type “char” is an 8-bit that may be signed or unsigned. The data type of signed is assumed if not explicitly declared as unsigned.
There are two methods for handling serial data—a character at a time or a line at a time. The programs provided by the code found in the link above to PIC UART Code handles both character based and string based drivers for the serial port. There is no constraint for the value of data communicated using character the based functions getU1 and putU1. The value of data communicated using string based functions, puts and getstrU1, are constrained to ASCII encoded characters.
Normally, the getcU1 and getstrU1 functions are both blocking functions. This means that when the function getcU1 is called, it will wait indefinitely for a serial character to be received. Since getstrU1 calls the function, getcU1 waits for all characters in the string to be received, it too is a blocking function. The code provided in the PIC UART code page has been written specifically to avoid the blocking problem. Greater detail on the implementation of the non-blocking getcU1 and getstrU1 functions is provided in the code documentation.
Writing an ASCII string to the serial port is handled by the puts
function. ASCII control characters, carriage return (CR,
0x0D, '\r'
), and line feed (LF,
0x0A, '\n'
) are automatically added to the end of the
text string. The prototype for this function is
int putsU1(const char *s)
. Even though this prototype implies that a
value is returned, in reality the value returned has no meaning. The character
array, str, must be a null terminated text string. Two examples of
using the putsU1 function are shown in Listing 1.
Listing 1. Examples of methods to use the putsU1 function.
putsU1("Hello World"); // Constant test string
char str[32]; // Size of the character array must anticipate the
// longest possible string plus 1.
sprintf(str,"Hello World");
putsU1(str); // Variable text string set to "Hello World"
Both of the methods shown in Listing 1 are equivalent to
printf("Hello World\r\n");
.
The getstrU1 function will return an entire string of text. When the string of data is sent over the serial port, the end of the text line is indicated by the carriage return character or when the number of characters received equals the value specified by a parameter to limit the string length. (This string limit value prevents buffer overflows that cause systems to crash.) When a carriage return character is received, it is replaced in the receive string array by a null character (value = 0x00). In the case where the number of characters received reaches the specified limit, the last element in the receiving string array is set to zero (null). The line feed ASCII control character is ignored. The getstrU1 function also processes the BACKSPACE character such that a destructive backspace operation is implemented. (Characters are deleted during backspace operations. This operation is sometimes referred to as destructive backspace that implements the same operation as the backspace key on PC terminal emulator.)
The prototype for the getstrU1 is
char * getstrU1(char *s, int len);
The function returns a pointer to
the character string str. Listing 2 shows how to call the
getstrU1 function.
Listing 2. Example code for using the getstrU1 function.
char str[20]; // Buffer size is set to hold the maximum expected
// number of characters per line plus 1.
While (!getstrU1(str, sizeof(str)));
Passing numerical data over text strings can be difficult without a mechanism to parse the data from the fields of data in the string. The Microchip XC32 compiler supports the sscanf function. To use sscanf, you must include stdio.h at the top of the program. Additional string functions such as strcmp(s1,s2) (string compare) and strcpy (s1,s2) (string copy) are available by including <string.h>. The reader is referred to the Microchip 32-Bit Language Tools Library guide for additional information on functions to assist processing string data. The code shown in Listing 3 illustrates the use of the sscanf function. For this illustration, assume that the text 123 444 dog cat is sent to the PIC32MX7 UART.
Listing 3. Example code for using the stringscanf function.
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[21]; // Buffer size is set to hold the maximum expected
// number of characters per line plus the NULL terminator
int x1, x2;
char s1[5], s2[5];
while(!getstrU1(str, ( sizeof(str) / sizeof(str[0]) ) ) );
sscanf(str,"%d %d %s %s", &x1, &x2, s1, s2);
}
The format of the string to be parsed with the sscanf function indicates that two integer values will be followed by two strings. The ASCII space character for this example is the delimiter (field separator). After the scanf instruction has executed, x1 will equal 123 and x2 will equal 444. The character arrays s1 and s2 will contain the null terminated strings dog and cat respectively. These strings s1 and s2 must be of sufficient length to hold the maximum number of characters parsed into these strings to avoid run time errors. Notice the arguments in the variable list are passed by reference. When entering the input string, the space character is the delimiter or separator between parameters. If more than one space character is entered between parameters, the additional space characters are ignored.
The UART peripheral must be initialized to set the communications bit rate, the parity option, and the number of data bits to send and receive. Additionally, the transmit and receive devices have separable enabled control bits. The XC32 peripheral library provides the UART open function shown in Listing 4.
OpenUART1( (UART_EN | UART_BRGH_FOUR | UART_NO_PAR_8BIT),
(UART_RX_ENABLE | UART_TX_ENABLE), brg );
The UART_EN bit sets the transmit and receive I/O pins for their alternate function to support the UART communications. The parameter, UART_BRGH_FOUR, specifies that the reconstruction clock rate as four times the serial port bit rate. The reconstruction clock is used to set the sample points in the middle of the symbol, as illustrated in Fig. 1. Thus, the third parameter in the OpenUART function, brg, is determined by dividing the peripheral bus clock by four times the desired bit rate.
The UART_NO_PAR_8BIT option specifies both the data size and no parity bit for error detection. To use even parity error detection, substitute UART_EVEN_PAR_8BIT. Or, for odd parity, use UART_ODD_PAR_8BIT in this parameter field.
The link on PIC UART Code, located near the top of the page, contains the code for UART operations. UART1 is initialized by calling the function initialize_uart1(int bit_rate, int parity) from the user’s application. The parity parameter can be specified as NO_PARITY, EVEN_PARITY, or ODD_PARITY. Other serial communication functions provided in the code shown in the PIC UART code page are for transmitting and receiving single characters and sending and receiving text strings.
The serial receive functions, getcU1 and getstrU1, were developed specifically to be non-blocking. They will return a value to the calling function indicating whether there is new data available. These functions return a false value if no new data has been received. When new data has been received, a logical true is returned. The actual character or string is contained in a variable that is passed by reference.
The code provided in the PIC UART code page can be easily converted to use UART 2 by changing all references to UART1 to UART2 and U1 to U2.
The data that is entered on the PC using the terminal emulation program will be echoed to the LCD, where it will be decoded to set the stepper motor parameters’ direction, mode, and stepper motor speed. The code that reads and decodes the serial data and sets the stepper motor operating parameters will run in the background while all of the preemptive code from Project 5 will run in the foreground. For this project, you will need to replace fixed pre-computed step delay times with a formula that computes the step delay time at run time from a range of RPM values.
After you have correctly merged the Project 5 code with the UART handling code, you will observe that although the program is waiting for data from the UART (due to the use of preemption) the stepper motor will continue to run and button inputs will continue to be detected.
The specifications require that the LCD be written to from the while(1) loop in the main function and also from the decode buttons function called by the change-notice (CN) ISR. Since all LCD operations are non-reentrant, the operations involving the LCD in the main function must be protected from CN interrupts. This is most efficiently accomplished by disabling the CN interrupts using the macro provided by the C32 peripheral library, mCNIntEnable(FALSE) to disable CN interrupts and mCNIntEnable(TRUE) to re enable CN interrupts.
To prevent becoming overwhelmed by the magnitude of the number of files in this project, it is suggested that you start with the UART function—sending and receiving text strings and using the sscanf function to parse the direction, mode, and stepper motor speed data. Temporarily comment out the portions of the initialization function that enable the Timer 1 and CN interrupts.
Following the development of the UART code, add the LCD operations. Finally, add the Project 5 operations by removing the comments for the section of code that enables the interrupts. Remember to call the initializing functions for the UART and the LCD prior to attempting to use those resources.
The hardware configuration for Project 7 is shown in Fig. 6. It requires all of the code and hardware used for Projects 5 and 6 in addition to hardware and software to support the serial communications with the PC. This project will require you to input text data from the serial port that will set the direction, mode, and speed of the stepper motor. This interface will be in addition to all of the controls provided in Project 5. The text from the serial port will be echoed to the LCD. It would be good for you to review the documentation on how the following text manipulating functions are implemented: printf, sprintf, scanf, and strcmp.
The functional specifications are:
The direction and mode string variables can be decoded using the string compare function strcmp. An example of using this function would be:
x = strcmp(mode_txt,"FULL");
Only if the string of data in mode_txt is exactly equal to FULL will the value of “x” equal zero. You must include <string.h> to be able to use this function.
ANSWER: The data rate is 19200 (with parity), so
the maximum speed that a new character can be received is 1745 characters per
second or once every 0.57 ms. However, the characters are sent at the speed of
the person typing on the terminal keyboard. A professional typist is capable
of up to 60 words per minute. Using a conversion factor of five characters per
word, the effective data rate is 50 bits per second, or a byte of new data
each 20 ms. The delay in the button debounce function is 20 ms. Hence, it
would be possible for data byes to be missed for fast terminal operators. This
does not include other tasks that the processor must complete in response to
the serial data and periodic interrupts. If the communications are being generated automatically and can be sent at
the maximum speed, getstrU1 should be modified to generate an
interrupt whenever a new byte of data is received. A flag will still be needed
to indicate when the text string is completely received and is ready for
processing.