1.主函数流程
此程序的作用是实现RTC计时功能。运行程序后,依次设定小时、分钟、秒、日、月、年,程序会按照设定时间开始计时,并将实时时间打印出来。主函数如下:
int main(void)
{
// 初始化串口终端 使用串口2
UARTStdioInit();
// 打印串口终端信息
UARTPuts("Tronlong RTC Application......\r\n", -2);
// 实时时钟初始化
RTCInit();
// DSP 中断初始化
InterruptInit();
// 实时时钟中断初始化
RTCInterruptInit();
// 主循环
for(;;)
{
}
}
2.初始化串口终端
主函数中,首先初始化串口终端,使用串口2,初始化串口终端函数UARTStdioInit可参考这里:
3.打印串口终端信息
然后程序开始打印串口终端信息,进行提示,UARTPuts函数在demo\StarterWare\Source\StarterWare\Utils\uartStdio.c文件中,该API可参考这里:
4.实时时钟初始化
实时时钟初始化函数RTCInit对RTC模块进行初始化,RTCInit函数如下:
void RTCInit(void)
{
unsigned int UserTime = 0, UserCalendar = 0;
// 禁用 RTC 寄存器写保护
RTCWriteProtectDisable(SOC_RTC_0_REGS);
// 软件复位并使能 RTC
RTCEnable(SOC_RTC_0_REGS);
// 延时 最小3倍 32KH 时钟周期
Delay(0xFFFF);
UserTime = UserTimeInfoGet();
UserCalendar = UserCalendarInfoGet();
// 设置时间日期
RTCCalendarSet(SOC_RTC_0_REGS, UserCalendar);
RTCTimeSet(SOC_RTC_0_REGS, UserTime);
// 使能 32KHz 计数器
RTCRun(SOC_RTC_0_REGS);
该函数执行流程如下:
4.1 禁用RTC寄存器写保护
禁用RTC寄存器写保护函数RTCWriteProtectDisable如下:
void RTCWriteProtectDisable(unsigned int baseAdd)
{
HWREG(baseAdd + RTC_KICK0) = RTC_KICK0R_KEY;
HWREG(baseAdd + RTC_KICK1) = RTC_KICK1R_KEY;
}
将相应的密钥值(key0和key1)写往KICK0和KICK1寄存器,解锁对RTC寄存器的写保护。
(指南P1240)
4.2 软件复位并使能RTC
RTC使能函数RTCEnable如下:
void RTCEnable(unsigned int baseAdd)
{
volatile unsigned int splitPower = 0;
if(RTC_REV_AM1808 == RtcVersionGet())
{
splitPower = RTC_CTRL_SPLITPOWER;
HWREG(baseAdd + RTC_OSC) |= RTC_OSC_SWRESET;
}
HWREG(baseAdd + RTC_CTRL) &= ~(RTC_CTRL_RTCDISABLE);
HWREG(baseAdd + RTC_CTRL) |= splitPower;
}
函数首先判断集成RTC的SOC是否为AM1808处理器,如果是,则设置CTRL寄存器的SPLITPOWER位为1,使能split power(RTC独立供电),同时设置OSC寄存器的SWRESET位为1,对RTC进行软件复位。这里RtcVersionGet函数返回的是1,所以将SPLITPOWER位置1,同时对RTC软件复位。
(指南P1251)
(指南P1256)
RtcVersionGet函数在Platform工程的RTC.c文件中,该函数如下:
unsigned int RtcVersionGet(void)
{
return 1;
}
4.3 延时
对RTC进行软件复位后,必须等待至少3个RTC时钟周期的延时。因此调用延时函数Delay。
4.4 获取时间和日期
4.4.1 获取时间
延时完成后,可以对RTC的寄存器进行访问了,首先要设置RTC的时间和日期,函数从串口获取要设置的时间和日期。UserTimeInfoGet函数获取RTC当前时间,UserCalendarInfoGet函数获取RTC当前日期。UserTimeInfoGet函数如下:
unsigned int UserTimeInfoGet()
{
unsigned char hour[2] = {0}, minute[2] = {0}, second[2] = {0};
unsigned int hourTime = 0, minTime = 0, secTime = 0;
unsigned int time = 0;
int i = 0;
UARTPuts("\n\nEnter the time in 24 hour format.\r\n", -1);
UARTPuts("Example (hh:mm:ss) 20:15:09\r\n", -1);
UARTPuts("\r\nEnter Hours: \r\n", -2);
do
{
hour[i] = UARTGetc();
UARTPutc(hour[i]);
i++;
}while((i < 2) && (hour[i-1] != '\r'));
UARTPuts("\r\nEnter Minutes:\r\n", -2);
i = 0;
do
{
minute[i] = UARTGetc();
UARTPutc(minute[i]);
i++;
}while((i < 2) && (minute[i-1] != '\r'));
UARTPuts("\r\nEnter Seconds:\r\n", -1);
i = 0;
do
{
second[i] = UARTGetc();
UARTPutc(second[i]);
i++;
}while((i < 2) && (second[i-1] != '\r'));
if(hour[0] != '\r')
{
hourTime = (ASCIIToInt(hour[0]) << 0x04);
if(hour[1] != '\r')
{
hourTime |= ASCIIToInt(hour[1]);
}
else
{
hourTime = hourTime >> 0x04;
}
}
if(minute[0] != '\r')
{
minTime = (ASCIIToInt(minute[0]) << 0x04);
if(minute[1] != '\r')
{
minTime |= ASCIIToInt(minute[1]);
}
else
{
minTime = minTime >> 0x04;
}
}
if(second[0] != '\r')
{
secTime = (ASCIIToInt(second[0]) << 0x04);
if(second[1] != '\r')
{
secTime |= ASCIIToInt(second[1]);
}
else
{
secTime = secTime >> 0x04;
}
}
time = (hourTime << HOUR_SHIFT);
time |= (minTime << MINUTE_SHIFT);
time |= (secTime << SECOND_SHIFT);
return time;
}
UARTGetc函数参考这篇博文:
UARTPutc函数和UARTPuts函数参考这篇博文:
函数首先依次获取时、分、秒数据(由用户输入),然后将从串口获取的ASCII码形式的时间信息转换为整型数据。ASCII码转整型数据函数ASCIIToInt如下:
unsigned char ASCIIToInt(unsigned char byte)
{
unsigned char retVal = 0;
// 数字 0-9
if((byte >= 0x30) && (byte <= 0x39))
{
retVal = byte - 0x30;
}
// 字母 A-Z
else if((byte >= 0x41) && (byte <= 0x46))
{
retVal = byte - 0x37;
}
return retVal;
}
最后将时分秒(一共24位数据,各8位)一起拼接到time变量中并返回。
4.4.2 获取日期
UserCalendarInfoGet函数获取用户设置的日期,函数如下:
unsigned int UserCalendarInfoGet()
{
unsigned int calendar = 0;
unsigned char dayOfMonth[2] = {0}, monthArr[2] = {0}, yearArr[2] = {0};
unsigned char dotwArr[2] = {0};
unsigned int dom = 0, month = 0, year = 0, dotw = 0;
int j = 0;
UARTPuts("\r\n\r\nEnter the calendar information.\r\n", -2);
UARTPuts("Example (DD:MM:YY) 31:03:73\r\n", -2);
UARTPuts("\r\nEnter the day of the month: \r\n", -2);
do
{
dayOfMonth[j] = UARTGetc();
UARTPutc(dayOfMonth[j]);
j++;
}while((j < 2) && (dayOfMonth[j-1] != '\r'));
j = 0;
UARTPuts("\r\nEnter the month (Jan=01, Dec=12):\r\n", -2);
do
{
monthArr[j] = UARTGetc();
UARTPutc(monthArr[j]);
j++;
}while((j < 2) && (monthArr[j-1] != '\r'));
j = 0;
UARTPuts("\r\nEnter the year (Ex: 2010=10, 1987=87:):\r\n", -1);
do
{
yearArr[j] = UARTGetc();
UARTPutc(yearArr[j]);
j++;
}while((j < 2) && (yearArr[j-1] != '\r'));
j = 0;
UARTPuts("\r\nEnter the Day of the Week (Ex:Sun=00, Sat=06):\r\n", -3);
do
{
dotwArr[j] = UARTGetc();
UARTPutc(dotwArr[j]);
j++;
}while((j < 2) && (dotwArr[j-1] != '\r'));
if(dayOfMonth[0] != '\r')
{
dom = (ASCIIToInt(dayOfMonth[0]) << 0x04);
if(dayOfMonth[1] != '\r')
{
dom |= ASCIIToInt(dayOfMonth[1]);
}
else
{
dom = dom >> 0x04;
}
}
if(monthArr[0] != '\r')
{
month = (ASCIIToInt(monthArr[0]) << 0x04);
if(monthArr[1] != '\r')
{
month |= ASCIIToInt(monthArr[1]);
}
else
{
month = month >> 0x04;
}
}
if(yearArr[0] != '\r')
{
year = (ASCIIToInt(yearArr[0]) << 0x04);
if(yearArr[1] != '\r')
{
year |= ASCIIToInt(yearArr[1]);
}
else
{
year = year >> 0x04;
}
}
if(dotwArr[0] != '\r')
{
dotw = (ASCIIToInt(dotwArr[0]) << 0x04);
if(dotwArr[1] != '\r')
{
dotw |= ASCIIToInt(dotwArr[1]);
}
else
{
dotw = dotw >> 0x04;
}
}
calendar = dom << DAY_SHIFT;
calendar |= month << MONTH_SHIFT;
calendar |= year << YEAR_SHIFT;
calendar |= dotw;
UARTPuts("\r\n\r\n", -1);
return calendar;
}
} 获取日期函数与获取时间函数基本一样,不再细述。
4.5 设置时间日期
4.5.1 设置日期
设置RTC的时间和日期,设置日期函数RTCCalendarSet如下:
void RTCCalendarSet(unsigned int baseAdd, unsigned int calendar)
{
while(IS_RTC_BUSY);
/* Writing to YEAR register.*/
HWREG(baseAdd + RTC_YEAR) = (calendar & YEAR_MASK) >> YEAR_SHIFT;
/* Writing to MONTH register.*/
HWREG(baseAdd + RTC_MONTH) = (calendar & MONTH_MASK) >> MONTH_SHIFT;
/* Writing to DAY register.*/
HWREG(baseAdd + RTC_DAY) = (calendar & DAY_MASK) >> DAY_SHIFT;
/* Writing to DOTW register.*/
HWREG(baseAdd + RTC_DOTW) = (calendar & DOTW_MASK);
}
函数首先判断STATUS寄存器的BUSY位是否为1,如果是,则RTC正忙,等待RTC为free再往下执行。
(指南P1252)
从calender变量中分别提取出年、月、日信息,对YEAR、MONTH、DAY寄存器进行设置,并设置DOTW寄存器,设置日期是星期几。这四个寄存器都是以BCD码的形式存储的。
(指南P1245)
(指南P1245)
(指南P1246)
(指南P1246)
4.5.2 设置时间
设置时间函数RTCTimeSet函数如下:
void RTCTimeSet(unsigned int baseAdd, unsigned int time)
{
volatile unsigned int splitPower = 0;
if(RTC_REV_AM1808 == RtcVersionGet())
{
splitPower = RTC_CTRL_SPLITPOWER;
}
/* Stop the RTC.*/
HWREG(baseAdd + RTC_CTRL) &= ~(RTC_CTRL_RUN);
/* Enable split power mode.*/
HWREG(baseAdd + RTC_CTRL) |= splitPower;
/* Writing to SECOND register.*/
HWREG(baseAdd + RTC_SECOND) = (time & SECOND_MASK) >> SECOND_SHIFT;
/* Writing to MINUTE register.*/
HWREG(baseAdd + RTC_MINUTE) = (time & MINUTE_MASK) >> MINUTE_SHIFT;
/* Writing to HOUR register.*/
HWREG(baseAdd + RTC_HOUR) = (((time & HOUR_MASK) >> HOUR_SHIFT) |
(time & MERIDIEM_MASK));
}
函数首先设置CTRL[RUN]位为0,停止RTC计数器。接着设置CTRL[SPLITPOWER]位为1,使能RTC独立供电模式(split power mode,用板载纽扣电池供电)。然后从time变量中分别提取出时、分、秒数据,对时分秒寄存器进行设置。时分秒寄存器都是以BCD码的形式存储的。
(指南P1243)
(指南P1244)
在设置时寄存器时,设置MERIDIEM位,在使能12小时模式(12-hour mode)时,该位指示当前小时值是AM还是PM。
4.6 使能32KHz计数器
完成对RTC相关寄存器的设置后,可以使能RTC的32KHz计数器,让RTC开始计时了。RTCRun函数使能RTC32KHz计数器,函数如下:
void RTCRun(unsigned int baseAdd)
{
volatile unsigned int splitPower = 0;
if(RTC_REV_AM1808 == RtcVersionGet())
{
splitPower = RTC_CTRL_SPLITPOWER;
}
/*
** BUSY bit in STATUS register should be checked for being low
** only when RTC is running. The current function is invoked when
** RTC is stopped. Thus, BUSY status need not be checked.
*/
/* Setting the RUN bit in CTRL register.*/
HWREG(baseAdd + RTC_CTRL) |= (RTC_CTRL_RUN | splitPower);
}
函数设置CTRL[RUN]位为1,运行RTC计数器。
(指南P1235)
5.DSP中断初始化
DSP中断初始化函数InterruptInit参考这里:
6.实时时钟中断初始化
RTC有2路中断源,一路为Alarm Interrputs,用于设置闹钟;另一路为Periodic Interrputs,用于定时中断。实时时钟中断初始化函数RTCInterruptInit如下:
void RTCInterruptInit(void)
{
// 注册中断服务函数
IntRegister(C674X_MASK_INT4, RTCIsr);
// 映射中断到 DSP 可屏蔽中断
IntEventMap(C674X_MASK_INT4, SYS_INT_RTC_IRQS);
// 使能 DSP 可屏蔽中断
IntEnable(C674X_MASK_INT4);
// 使能实时时钟中断 每秒产生一次中断
RTCIntTimerEnable(SOC_RTC_0_REGS, RTC_INT_EVERY_SECOND);
}
函数首先注册CPU可屏蔽中断INT4的中断服务函数为RTCIsr,然后将RTC中断SYS_INT_RTC_IRQS(#63)映射到INT4,再使能INT4。最后,设置RTC的INTERRUPT寄存器的INTERRUPT[TIMER]位为1,使能RTC周期中断,同时设置EVERY位,设置中断周期值。
(指南P1253)
RTCIntTimerEnable函数如下:
void RTCIntTimerEnable(unsigned int baseAdd, unsigned int timerPeriod)
{
/*
** Writing to INTERRUPT register requires that BUSY bit in STATUS register
** is low.
*/
while(IS_RTC_BUSY);
HWREG(baseAdd + RTC_INTERRUPT) |= RTC_INTERRUPTS_TIMER;
HWREG(baseAdd + RTC_INTERRUPT) |= (timerPeriod & RTC_INTERRUPTS_EVERY);
}
7.中断服务函数
7.1 清除中断标志
中断服务函数RTCIsr如下:
void RTCIsr(void)
{
unsigned int timeValue = 0, calendarValue = 0;
IntEventClear(SYS_INT_RTC_IRQS);
// 读当前时间
timeValue = RTCTimeGet(SOC_RTC_0_REGS);
// 解析时间
TimeResolve(timeValue);
// 读当前日期
calendarValue = RTCCalendarGet(SOC_RTC_0_REGS);
UARTPuts(" ", -2);
// 解析日期
CalendarResolve(calendarValue);
UARTPuts("\r", -2);
}
函数首先清除中断标志,IntEventClear函数参考这两篇博文:
7.2 读当前时间
然后函数读出当前时间,RTCTimeGet函数如下:
unsigned int RTCTimeGet(unsigned int baseAdd)
{
unsigned int sec = 0, min = 0, hour = 0, mer = 0;
/* Reading from SECOND register.*/
sec = HWREG(baseAdd + RTC_SECOND);
sec = (sec & (RTC_SECOND_SEC1 | RTC_SECOND_SEC0)) << SECOND_SHIFT;
/* Reading from MINUTE register.*/
min = HWREG(baseAdd + RTC_MINUTE);
min = (min & (RTC_MINUTE_MIN1 | RTC_MINUTE_MIN0)) << MINUTE_SHIFT;
/* Reading from HOUR register.*/
hour = HWREG(baseAdd + RTC_HOUR);
hour = (hour & (RTC_HOUR_HOUR1 | RTC_HOUR_HOUR0)) << HOUR_SHIFT;
/* Reading MERIDIEM bit in HOUR register.*/
mer = (HWREG(baseAdd + RTC_HOUR) & RTC_HOUR_MERIDIEM);
return ( sec | min | hour | mer);
}
函数读取时分秒寄存器并将时分秒以及Meridiem值拼接到一起返回给timeValue。
7.3 解析时间
再对时间进行解析,解析时间函数TimeResolve如下:
void TimeResolve(unsigned int timeValue)
{
unsigned char timeArray[3] = {0};
unsigned char bytePrint[2] = {0};
unsigned int count = 0, i = 0;
unsigned int asciiTime = 0;
timeArray[0] = (unsigned char)((timeValue & MASK_HOUR) >> HOUR_SHIFT);
timeArray[1] = (unsigned char)((timeValue & MASK_MINUTE) >> MINUTE_SHIFT);
timeArray[2] = (unsigned char)((timeValue & MASK_SECOND) >> SECOND_SHIFT);
while(count < 3)
{
i = 0;
asciiTime = intToASCII(timeArray[count]);
bytePrint[0] = (unsigned char)((asciiTime & 0x0000FF00) >> 0x08);
bytePrint[1] = (unsigned char)(asciiTime & 0x000000FF);
while(i < 2)
{
UARTPutc(bytePrint[i]);
i++;
}
count++;
if(count != 3)
{
UARTPutc(':');
}
else
{
UARTPutc(' ');
}
}
}
该函数将时分秒信息分别从timeValue中提取出来,并将它们由整型(int型)转换为ASCII码型,再输出到串口。数字转换为ASCII码函数intToASCII如下:
unsigned int intToASCII(unsigned char byte)
{
unsigned int retVal = 0;
unsigned char lsn = 0, msn = 0;
lsn = (byte & 0x0F);
msn = (byte & 0xF0) >> 0x04;
retVal = (lsn + 0x30);
retVal |= ((msn + 0x30) << 0x08);
return retVal;
}
7.4 读当前日期
接着读当前日期,读当前日期函数RTCCalendarGet如下:
unsigned int RTCCalendarGet(unsigned int baseAdd)
{
unsigned int calVal = 0;
/* Reading from the DAY register.*/
calVal = (HWREG(baseAdd + RTC_DAY) & (RTC_DAY_DAY1 | RTC_DAY_DAY0)) << \
DAY_SHIFT;
/* Reading from MONTH register.*/
calVal |= (HWREG(baseAdd + RTC_MONTH) & (RTC_MONTH_MONTH1 |
RTC_MONTH_MONTH0)) << MONTH_SHIFT;
/* Reading from YEAR register.*/
calVal |= (HWREG(baseAdd + RTC_YEAR) & (RTC_YEAR_YEAR1 |
RTC_YEAR_YEAR0)) << YEAR_SHIFT;
/* Reading from DOTW register.*/
calVal |= (HWREG(baseAdd + RTC_DOTW) & RTC_DOTW_DOTW);
return calVal;
}
函数从DAY、MONTH、YEAR、DOTW寄存器中分别读取日、月、年、星期值,并拼接到calVal变量中,再返回。
7.5 解析日期
解析日期函数CalendarResolve如下:
void CalendarResolve(unsigned int calendarValue)
{
unsigned char calendarArray[3] = {0};
unsigned int asciiCalendar = 0;
unsigned int count = 0, j = 0;
unsigned int dotwValue = 0;
char bytePrint[2] = {0};
char dotwString[3] = {0};
calendarArray[0] = (unsigned char)((calendarValue & MASK_DAY) >> DAY_SHIFT);
calendarArray[1] = (unsigned char)((calendarValue & MASK_MONTH) >> MONTH_SHIFT);
calendarArray[2] = (unsigned char)((calendarValue & MASK_YEAR) >> YEAR_SHIFT);
dotwValue = (calendarValue & MASK_DOTW);
switch(dotwValue)
{
case 0x00:
dotwString[0] = 'S';
dotwString[1] = 'u';
dotwString[2] = 'n';
break;
case 0x01:
dotwString[0] = 'M';
dotwString[1] = 'o';
dotwString[2] = 'n';
break;
case 0x02:
dotwString[0] = 'T';
dotwString[1] = 'u';
dotwString[2] = 'e';
break;
case 0x03:
dotwString[0] = 'W';
dotwString[1] = 'e';
dotwString[2] = 'd';
break;
case 0x04:
dotwString[0] = 'T';
dotwString[1] = 'h';
dotwString[2] = 'u';
break;
case 0x05:
dotwString[0] = 'F';
dotwString[1] = 'r';
dotwString[2] = 'i';
break;
case 0x06:
dotwString[0] = 'S';
dotwString[1] = 'a';
dotwString[2] = 't';
default:
break;
}
while(count < 3)
{
j = 0;
asciiCalendar = intToASCII(calendarArray[count]);
bytePrint[0] = (char)((asciiCalendar & 0x0000FF00) >> 0x08);
bytePrint[1] = (char)(asciiCalendar & 0x000000FF);
while(j < 2)
{
UARTPutc(bytePrint[j]);
j++;
}
count++;
if(count != 3)
{
UARTPutc('-');
}
else
{
UARTPutc(' ');
}
}
UARTprintf("%s ", dotwString);
}
函数从calenderValue中分别将年月日提取出来存到calenderArray数组中,将星期值提取处理到dotwValue中,根据星期值设置要打印星期信息数组dotwString。再将日期数组各个元素从整型转到ASCII码型,并将它们打印出来。最后将星期值打印出来,UARTprintf函数在\demo\StarterWare\Source\StarterWare\Utils工程下的uartStdio.c文件中,函数如下:
void UARTprintf(const char *pcString, ...)
{
unsigned int idx, pos, count, base, neg;
char *pcStr, pcBuf[16], cFill;
va_list vaArgP;
int value;
/* Start the varargs processing. */
va_start(vaArgP, pcString);
/* Loop while there are more characters in the string. */
while(*pcString)
{
/* Find the first non-% character, or the end of the string. */
for(idx = 0; (pcString[idx] != '%') && (pcString[idx] != '\0'); idx++)
{
}
/* Write this portion of the string. */
UARTwrite(pcString, idx);
/* Skip the portion of the string that was written. */
pcString += idx;
/* See if the next character is a %. */
if(*pcString == '%')
{
/* Skip the %. */
pcString++;
/* Set the digit count to zero, and the fill character to space
* (i.e. to the defaults). */
count = 0;
cFill = ' ';
/* It may be necessary to get back here to process more characters.
* Goto's aren't pretty, but effective. I feel extremely dirty for
* using not one but two of the beasts. */
again:
/* Determine how to handle the next character. */
switch(*pcString++)
{
/* Handle the digit characters. */
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
/* If this is a zero, and it is the first digit, then the
* fill character is a zero instead of a space. */
if((pcString[-1] == '0') && (count == 0))
{
cFill = '0';
}
/* Update the digit count. */
count *= 10;
count += pcString[-1] - '0';
/* Get the next character. */
goto again;
}
/* Handle the %c command. */
case 'c':
{
/* Get the value from the varargs. */
value = va_arg(vaArgP, unsigned int);
/* Print out the character. */
UARTwrite((char *)&value, 1);
/* This command has been handled. */
break;
}
/* Handle the %d command. */
case 'd':
{
/* Get the value from the varargs. */
value = va_arg(vaArgP, unsigned int);
/* Reset the buffer position. */
pos = 0;
/* If the value is negative, make it positive and indicate
* that a minus sign is needed. */
if((int)value < 0)
{
/* Make the value positive. */
value = -(int)value;
/* Indicate that the value is negative. */
neg = 1;
}
else
{
/* Indicate that the value is positive so that a minus
* sign isn't inserted. */
neg = 0;
}
/* Set the base to 10. */
base = 10;
/* Convert the value to ASCII. */
goto convert;
}
/* Handle the %s command. */
case 's':
{
/* Get the string pointer from the varargs. */
pcStr = va_arg(vaArgP, char *);
/* Determine the length of the string. */
for(idx = 0; pcStr[idx] != '\0'; idx++)
{
}
/* Write the string. */
UARTwrite(pcStr, idx);
/* Write any required padding spaces */
if(count > idx)
{
count -= idx;
while(count--)
{
UARTwrite((const char *)" ", 1);
}
}
/* This command has been handled. */
break;
}
/* Handle the %u command. */
case 'u':
{
/* Get the value from the varargs. */
value = va_arg(vaArgP, unsigned int);
/* Reset the buffer position. */
pos = 0;
/* Set the base to 10. */
base = 10;
/* Indicate that the value is positive so that a minus sign
* isn't inserted. */
neg = 0;
/* Convert the value to ASCII. */
goto convert;
}
/* Handle the %x and %X commands. Note that they are treated
* identically; i.e. %X will use lower case letters for a-f
* instead of the upper case letters is should use. We also
* alias %p to %x. */
case 'x':
case 'X':
case 'p':
{
/* Get the value from the varargs. */
value = va_arg(vaArgP, unsigned int);
/* Reset the buffer position. */
pos = 0;
/* Set the base to 16. */
base = 16;
/* Indicate that the value is positive so that a minus sign
* isn't inserted. */
neg = 0;
/* Determine the number of digits in the string version of
* the value. */
convert:
for(idx = 1;
(((idx * base) <= value) &&
(((idx * base) / base) == idx));
idx *= base, count--)
{
}
/* If the value is negative, reduce the count of padding
* characters needed. */
if(neg)
{
count--;
}
/* If the value is negative and the value is padded with
* zeros, then place the minus sign before the padding. */
if(neg && (cFill == '0'))
{
/* Place the minus sign in the output buffer. */
pcBuf[pos++] = '-';
/* The minus sign has been placed, so turn off the
* negative flag. */
neg = 0;
}
/* Provide additional padding at the beginning of the
* string conversion if needed. */
if((count > 1) && (count < 16))
{
for(count--; count; count--)
{
pcBuf[pos++] = cFill;
}
}
/* If the value is negative, then place the minus sign
* before the number. */
if(neg)
{
/* Place the minus sign in the output buffer. */
pcBuf[pos++] = '-';
}
/* Convert the value into a string. */
for(; idx; idx /= base)
{
pcBuf[pos++] = g_pcHex[(value / idx) % base];
}
/* Write the string. */
UARTwrite(pcBuf, pos);
/* This command has been handled. */
break;
}
/* Handle the %% command. */
case '%':
{
/* Simply write a single %. */
UARTwrite(pcString - 1, 1);
/* This command has been handled. */
break;
}
/* Handle all other commands. */
default:
{
/* Indicate an error. */
UARTwrite((const char *)"ERROR", 5);
/* This command has been handled. */
break;
}
}
}
}
/* End the varargs processing. */
va_end(vaArgP);
}
该函数以格式字符串所指定的形式将信息打印到串口。