C6748_RTC
1.主函数流程
此程序的作用是实现RTC计时功能。运行程序后,依次设定小时、分钟、秒、日、月、年,程序会按照设定时间开始计时,并将实时时间打印出来。主函数如下:
intmain(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函数如下:
voidRTCInit(void)
{
unsignedint 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如下:
voidRTCWriteProtectDisable(unsignedint 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如下:
voidRTCEnable(unsignedint baseAdd)
{
volatileunsignedint 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文件中,该函数如下:
unsignedintRtcVersionGet(void)
{
return1;
}
4.3 延时
对RTC进行软件复位后,必须等待至少3个RTC时钟周期的延时。因此调用延时函数Delay。
4.4 获取时间和日期
4.4.1 获取时间
延时完成后,可以对RTC的寄存器进行访问了,首先要设置RTC的时间和日期,函数从串口获取要设置的时间和日期。UserTimeInfoGet函数获取RTC当前时间,UserCalendarInfoGet函数获取RTC当前日期。UserTimeInfoGet函数如下:
unsignedintUserTimeInfoGet()
{
unsignedchar hour[2] = {0}, minute[2] = {0}, second[2] = {0};
unsignedint hourTime =0, minTime =0, secTime =0;
unsignedinttime=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);
returntime;
}
UARTGetc函数参考这篇博文:
UARTPutc函数和UARTPuts函数参考这篇博文:
函数首先依次获取时、分、秒数据(由用户输入),然后将从串口获取的ASCII码形式的时间信息转换为整型数据。ASCII码转整型数据函数ASCIIToInt如下:
unsignedcharASCIIToInt(unsignedchar byte)
{
unsignedchar retVal =0;
// 数字 0-9
if((byte >=0x30) && (byte <=0x39))
{
retVal = byte -0x30;
}
// 字母 A-Z
elseif((byte >=0x41) && (byte <=0x46))
{
retVal = byte -0x37;
}
return retVal;
}
最后将时分秒(一共24位数据,各8位)一起拼接到time变量中并返回。
4.4.2 获取日期
UserCalendarInfoGet函数获取用户设置的日期,函数如下:
unsignedintUserCalendarInfoGet()
{
unsignedint calendar =0;
unsignedchar dayOfMonth[2] = {0}, monthArr[2] = {0}, yearArr[2] = {0};
unsignedchar dotwArr[2] = {0};
unsignedint 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如下:
voidRTCCalendarSet(unsignedint baseAdd, unsignedint 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函数如下:
voidRTCTimeSet(unsignedint baseAdd, unsignedint time)
{
volatileunsignedint 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计数器,函数如下:
voidRTCRun(unsignedint baseAdd)
{
volatileunsignedint 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如下:
voidRTCInterruptInit(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函数如下:
voidRTCIntTimerEnable(unsignedint baseAdd, unsignedint 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如下:
voidRTCIsr(void)
{
unsignedint 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函数如下:
unsignedintRTCTimeGet(unsignedint baseAdd)
{
unsignedint 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如下:
voidTimeResolve(unsignedint timeValue)
{
unsignedchar timeArray[3] = {0};
unsignedchar bytePrint[2] = {0};
unsignedint count =0, i =0;
unsignedint asciiTime =0;
timeArray[0] = (unsignedchar)((timeValue & MASK_HOUR) >> HOUR_SHIFT);
timeArray[1] = (unsignedchar)((timeValue & MASK_MINUTE) >> MINUTE_SHIFT);
timeArray[2] = (unsignedchar)((timeValue & MASK_SECOND) >> SECOND_SHIFT);
while(count <3)
{
i =0;
asciiTime =intToASCII(timeArray[count]);
bytePrint[0] = (unsignedchar)((asciiTime &0x0000FF00) >>0x08);
bytePrint[1] = (unsignedchar)(asciiTime &0x000000FF);
while(i <2)
{
UARTPutc(bytePrint[i]);
i++;
}
count++;
if(count !=3)
{
UARTPutc(':');
}
else
{
UARTPutc(' ');
}
}
}
该函数将时分秒信息分别从timeValue中提取出来,并将它们由整型(int型)转换为ASCII码型,再输出到串口。数字转换为ASCII码函数intToASCII如下:
unsignedintintToASCII(unsignedchar byte)
{
unsignedint retVal =0;
unsignedchar lsn =0, msn =0;
lsn = (byte &0x0F);
msn = (byte &0xF0) >>0x04;
retVal = (lsn +0x30);
retVal |= ((msn +0x30) <<0x08);
return retVal;
}
7.4 读当前日期
接着读当前日期,读当前日期函数RTCCalendarGet如下:
unsignedintRTCCalendarGet(unsignedint baseAdd)
{
unsignedint 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如下:
voidCalendarResolve(unsignedint calendarValue)
{
unsignedchar calendarArray[3] = {0};
unsignedint asciiCalendar =0;
unsignedint count =0, j =0;
unsignedint dotwValue =0;
char bytePrint[2] = {0};
char dotwString[3] = {0};
calendarArray[0] = (unsignedchar)((calendarValue & MASK_DAY) >> DAY_SHIFT);
calendarArray[1] = (unsignedchar)((calendarValue & MASK_MONTH) >> MONTH_SHIFT);
calendarArray[2] = (unsignedchar)((calendarValue & MASK_YEAR) >> YEAR_SHIFT);
dotwValue = (calendarValue & MASK_DOTW);
switch(dotwValue)
{
case0x00:
dotwString[0] ='S';
dotwString[1] ='u';
dotwString[2] ='n';
break;
case0x01:
dotwString[0] ='M';
dotwString[1] ='o';
dotwString[2] ='n';
break;
case0x02:
dotwString[0] ='T';
dotwString[1] ='u';
dotwString[2] ='e';
break;
case0x03:
dotwString[0] ='W';
dotwString[1] ='e';
dotwString[2] ='d';
break;
case0x04:
dotwString[0] ='T';
dotwString[1] ='h';
dotwString[2] ='u';
break;
case0x05:
dotwString[0] ='F';
dotwString[1] ='r';
dotwString[2] ='i';
break;
case0x06:
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文件中,函数如下:
voidUARTprintf(constchar*pcString, ...)
{
unsignedint 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, unsignedint);
/* 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, unsignedint);
/* 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((constchar*)" ", 1);
}
}
/* This command has been handled. */
break;
}
/* Handle the %u command. */
case'u':
{
/* Get the value from the varargs. */
value =va_arg(vaArgP, unsignedint);
/* 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, unsignedint);
/* 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((constchar*)"ERROR", 5);
/* This command has been handled. */
break;
}
}
}
}
/* End the varargs processing. */
va_end(vaArgP);
}
该函数以格式字符串所指定的形式将信息打印到串口。