zmain_ext_addr()函数研究(转)

本文详细解析了CC2530芯片中IEEE地址的获取过程,包括从非易失性存储器读取、查找备用地址及随机生成地址等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原链接:http://bbs.feibit.com/thread-7139-1-1.html


4.4大致说了:CC2530芯片在TI出厂时已经预先烧写了 Primary IEEE address,这个64位地址是全球唯一的。这个地址在CC2530的FLASH信息页中,是只读的。但是用户貌似可以重新写这个预先烧写的Primary IEEE address。具体再来看看 Section 7.2

7.2中说Z-STACK通过4个步骤来确定设备的IEEE地址:
1.从Z-stack的NV中读取
2.从Second IEEE 的位置中寻找
3.在Primary IEEE 的位置寻找
4.由随机数产生器产生一个临时IEEE地址。
也就是说,ZigBee设备在上电后,首先会从NV中读取IEEE地址,如果读取失败,则从FLASH的Second IEEE 的存放位置读取IEEE地址,如果读取失败,则再从Primary IEEE 的存放位置读取IEEE,如果还是失败,则由随机数发生器产生一个临时IEEE地址。步骤2或者步骤3一旦有效并且使能了“NV_RESTORE”,就会把这个IEEE地址写入到NV中去。这样下次上电的时候,就可以通过步骤1从NV中直接读取 IEEE地址。
接下来我们再来看看每一个步骤具体是怎么实现的:

Step1 从Z-stack的NV中读取 IEEE地址: 源代码见 Z-stack 2.5.1.a --> ZMain.c --> main( ) -->zmain_ext_addr()


我将源代码拿上来,自己添加了注释。

  1. static void zmain_ext_addr(void)
  2. {
  3. uint8 nullAddr[Z_EXTADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  4. uint8 writeNV = TRUE;

  5. // First check whether a non-erased extended address exists in the OSAL NV.
  6. if ((SUCCESS != osal_nv_item_init(ZCD_NV_EXTADDR, Z_EXTADDR_LEN, NULL))|| //如果NV初始化失败
  7. (SUCCESS != osal_nv_read(ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, aExtendedAddress)) ||//或者NV读取失败
  8. (osal_memcmp(aExtendedAddress, nullAddr, Z_EXTADDR_LEN))) //或者NV没有被写过
  9. {
  10. // Attempt to read the extended address from the location on the lock bits page
  11. // where the programming tools know to reserve it.
  12. // 若NV读取IEEE地址失败,则从Secondary IEEE中读取,在FLASH最后的偏移24个地址的地方,即0x3FFE8~0x3FFEF
  13. HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_IEEE_OSET, aExtendedAddress, Z_EXTADDR_LEN);

  14. if (osal_memcmp(aExtendedAddress, nullAddr, Z_EXTADDR_LEN)) //如果Secondary IEEE 也是无效的则读取Primary IEEE
  15. {
  16. // Attempt to read the extended address from the designated location in the Info Page.
  17. // Primary IEEE 在信息页偏移0x0c-0x13的地方,即(0x7800+0x0c)=0x780c,这个地址是映射到Xdata上的,不是CODE地址
  18. if (!osal_memcmp((uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), nullAddr, Z_EXTADDR_LEN))
  19. {
  20. osal_memcpy(aExtendedAddress, (uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), Z_EXTADDR_LEN);
  21. }
  22. else// No valid extended address was found.如果Primary IEEE 还是无效,则产生随机地址,随机地址以0xF8开头
  23. {
  24. uint8 idx;

  25. #if !defined ( NV_RESTORE )
  26. writeNV = FALSE;// Make this a temporary IEEE address
  27. #endif

  28. /* Attempt to create a sufficiently random extended address for expediency.
  29. * Note: this is only valid/legal in a test environment and
  30. * must never be used for a commercial product.
  31. */
  32. for (idx = 0; idx < (Z_EXTADDR_LEN - 2);)
  33. {
  34. uint16 randy = osal_rand();
  35. aExtendedAddress[idx++] = LO_UINT16(randy);
  36. aExtendedAddress[idx++] = HI_UINT16(randy);
  37. }
  38. // Next-to-MSB identifies ZigBee devicetype.
  39. #if ZG_BUILD_COORDINATOR_TYPE && !ZG_BUILD_JOINING_TYPE
  40. aExtendedAddress[idx++] = 0x10;
  41. #elif ZG_BUILD_RTRONLY_TYPE
  42. aExtendedAddress[idx++] = 0x20;
  43. #else
  44. aExtendedAddress[idx++] = 0x30;
  45. #endif
  46. // MSB has historical signficance.
  47. aExtendedAddress[idx] = 0xF8;
  48. }
  49. }

  50. if (writeNV)
  51. {
  52. (void)osal_nv_write(ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, aExtendedAddress);
  53. }
  54. }

  55. // Set the MAC PIB extended address according to results from above.
  56. (void)ZMacSetReq(MAC_EXTENDED_ADDRESS, aExtendedAddress);
  57. }
复制代码
从代码中可以看到,第一个 if 从NV的 ZCD_NV_EXTADDR 中读取了 IEEE地址。
如果 NV 读取IEEE成功,则直接跳到最后,执行
(void)ZMacSetReq(MAC_EXTENDED_ADDRESS, aExtendedAddress); //将读取成功的 IEEE地址 写到MAC层的PIB属性中

如果 NV 读取失败,或者读取出来的值全为0xFF,则说明 NV中 ZCD_NV_EXTADDR 这个元素并没有被配置过,视为无效,那就从Step2 中读取 IEEE 地址

Step2 从Second IEEE 的位置中找到 IEEE 地址
这个Second IEEE到底在哪里呢,Z-Stack User's Guide - CC2530DB.pdf 的 7.2 中已经提到,这个位置是在 FLASH 地址最后置偏移 0x0018个地址的地方。拿CC2530F256来说,256K的FLASH,那偏移0x18地址的位置应该是:0x3FFE8,IEEE 地址长度是8个字节,所以 Second IEEE 地址的存放地址应该是 0x3FFE8 ~ 3FFEF。
有人可能会疑惑,为什么是偏移0x18个地址呢,这里我个人的理解是:0x18=24=16+8. 这里的8就是IEEE地址的长度,这个16应该是FLASH最后的加密位。
再从代码来看,第一个 if 满足之后便是下面这句:
HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_IEEE_OSET, aExtendedAddress, Z_EXTADDR_LEN);

这是直接读FLASH 的函数,从 HAL_FLASH_IEEE_PAGE 这一页的 HAL_FLASH_IEEE_OSET 位置来读取 Second IEEE
在来看看 HAL_FLASH_IEEE_PAGE 和 HAL_FLASH_IEEE_OSET 分别是什么
  1. // Re-defining Z_EXTADDR_LEN here so as not to include a Z-Stack .h file.
  2. #define HAL_FLASH_IEEE_SIZE 8
  3. #define HAL_FLASH_IEEE_PAGE (HAL_NV_PAGE_END+1)//127
  4. #define HAL_FLASH_IEEE_OSET (HAL_FLASH_PAGE_SIZE - HAL_FLASH_LOCK_BITS - HAL_FLASH_IEEE_SIZE)//(2048-16-8)=2024
复制代码
从宏定义来看,HAL_FLASH_IEEE_PAGE 是NV最后一页再加1,也就是127页,是FLASH的最后一页(1也是2048 byte),地址是 HAL_FLASH_PAGE_SIZE - HAL_FLASH_LOCK_BITS - HAL_FLASH_IEEE_SIZE,也就是地址最后减去16 字节的加密位和8字节的IEEE地址,即2048-24 = 2024, 这也验证了我之前step1 中的猜想。
第二个 if 是判断这个 Second IEEE 地址是否有效,如果有效,则到代码的最后将有效的 IEEE 地址写入 PIB 中,若无效则进入Step3

Step3 从Primary IEEE 的位置中找到 IEEE 地址
这个 Primary IEEE 地址到底又在什么地方呢,Z-Stack User's Guide - CC2530DB.pdf 的 7.2 中已经提到,Primary IEEE 位于 FLASH 信息页偏移 0x0c ~ 0x13 个地址的地方。那么这个 FLASH 信息页到底又在哪里呢,参照 CC2530 user's guide 的 2.2.2 CPU memery space ,可以知道, 这个 FLASH information page 是映射到 XDADA的 0x7800 ~ 0x7FFF 上的,那么偏移0x0c个地址,应该就是XData 的 0x780c ~ 0x7813 地址上。
再来看看源代码
  1. if(!osal_memcmp((uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), nullAddr, Z_EXTADDR_LEN))
  2. {
  3. osal_memcpy(aExtendedAddress, (uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), Z_EXTADDR_LEN);
  4. }
复制代码
[/code]
源代码中第三个if直接用osal_memcmp 将 Xdata 中 (P_INFORFAGE + HAL_INFOP_IEEE_OSET) 与 8个 0xFF作比较。这个(P_INFORFAGE + HAL_INFOP_IEEE_OSET) 到底又是什么呢,请看它的宏定义:
  1. #define P_INFOPAGEPXREG( 0x7800 )/* Pointer to Start of Flash Information Page */

  2. #define HAL_INFOP_IEEE_OSET 0xC
复制代码
很明显,这个地址便是 0x7800 + 0xc = 0x780c,正确。如果这个地址有效,就作为 IEEE地址 使用,若无效则需要进入Step4


Step4 随机得到这个 IEEE 地址

文档中说到,如果前面的step1 ~ step3 都失效,则只能随机产生这个 IEEE地址,随机产生的这个 IEEE 地址 是以 0XF8 开头的。并且这个 IEEE地址不会被保存到 NV 中,因此如果说这个 IEEE 地址时随机产生的,那么这个值 每次上电后都是随机产生的,即使你使能了“NV_RESTORN”也不会存到 NV 中。这样的话如果用于实际应用其实是很危险的,所以尽量不要这种情况发生。
接下来看看是怎么产生这个随机 IEEE 地址的:
  1. else// No valid extended address was found.如果Primary IEEE 还是无效,则产生随机地址,随机地址以0xF8开头
  2. {
  3. uint8 idx;

  4. #if !defined ( NV_RESTORE )
  5. writeNV = FALSE;// Make this a temporary IEEE address
  6. #endif

  7. /* Attempt to create a sufficiently random extended address for expediency.
  8. * Note: this is only valid/legal in a test environment and
  9. * must never be used for a commercial product.
  10. */
  11. for (idx = 0; idx < (Z_EXTADDR_LEN - 2);)
  12. {
  13. uint16 randy = osal_rand();
  14. aExtendedAddress[idx++] = LO_UINT16(randy);
  15. aExtendedAddress[idx++] = HI_UINT16(randy);
  16. }
  17. // Next-to-MSB identifies ZigBee devicetype.
  18. #if ZG_BUILD_COORDINATOR_TYPE && !ZG_BUILD_JOINING_TYPE
  19. aExtendedAddress[idx++] = 0x10;
  20. #elif ZG_BUILD_RTRONLY_TYPE
  21. aExtendedAddress[idx++] = 0x20;
  22. #else
  23. aExtendedAddress[idx++] = 0x30;
  24. #endif
  25. // MSB has historical signficance.
  26. aExtendedAddress[idx] = 0xF8;
  27. }
复制代码
这个 else 之后便是产生随机 IEEE 地址的过程。
首先代码禁止了 NV的存储。然后通过一个 for 循环 产生了 6byte的随机地址。注意这里为什么只有6byte,我们的IEEE地址不是8byte的嘛。不要忘记,文档中说过,这个随机 IEEE 地址是要以 0xf8 开头, 那还有一个字节干嘛去了呢,代码中应该能看到,这个字节用于表示不同的设备类型了,协调器是0x10 , 路由器是 0x20 ,终端节点则是 0x30
所以最后这个随机 IEEE 地址的格式是: 0xF8 + (设备类型) + 6byte 随机值。

/************************************************************************************************** Filename: ZMain.c Revised: $Date: 2010-09-17 16:25:30 -0700 (Fri, 17 Sep 2010) $ Revision: $Revision: 23835 $ Description: Startup and shutdown code for ZStack Notes: This version targets the Chipcon CC2530 Copyright 2005-2010 Texas Instruments Incorporated. All rights reserved. IMPORTANT: Your use of this Software is limited to those specific rights granted under the terms of a software license agreement between the user who downloaded the software, his/her employer (which must be your employer) and Texas Instruments Incorporated (the "License"). You may not use this Software unless you agree to abide by the terms of the License. The License limits your use, and you acknowledge, that the Software may not be modified, copied or distributed unless embedded on a Texas Instruments microcontroller or used solely and exclusively in conjunction with a Texas Instruments radio frequency transceiver, which is integrated into your product. Other than for the foregoing purpose, you may not use, reproduce, copy, prepare derivative works of, modify, distribute, perform, display or sell this Software and/or its documentation for any purpose. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED 揂S IS?WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. Should you have any questions regarding your right to use this Software, contact Texas Instruments Incorporated at www.TI.com. **************************************************************************************************/ /********************************************************************* * INCLUDES */ #ifndef NONWK #include "AF.h" #endif #include "hal_adc.h" #include "hal_flash.h" #include "hal_lcd.h" #include "hal_led.h" #include "hal_drivers.h" #include "OnBoard.h" #include "OSAL.h" #include "OSAL_Nv.h" #include "ZComDef.h" #include "ZMAC.h" /********************************************************************* * LOCAL FUNCTIONS */ static void zmain_ext_addr( void ); #if defined ZCL_KEY_ESTABLISH static void zmain_cert_init( void ); #endif static void zmain_dev_info( void ); static void zmain_vdd_check( void ); #ifdef LCD_SUPPORTED static void zmain_lcd_init( void ); #endif /********************************************************************* * @fn main * @brief First function called after startup. * @return don't care */ int main( void ) { // Turn off interrupts osal_int_disable( INTS_ALL );//关闭中断 // Initialization for board related stuff such as LEDs HAL_BOARD_INIT();//电路板初始化 // Make sure supply voltage is high enough to run zmain_vdd_check();//供电电压检测 // Initialize board I/O InitBoard( OB_COLD );//初始电路板IO口 // Initialze HAL drivers HalDriverInit();//初始化硬件抽样层驱动 // Initialize NV System osal_nv_init( NULL );//初始化NVFLASH // Initialize the MAC ZMacInit();//初始化MAC地址 // Determine the extended address zmain_ext_addr();//读取扩展地址 #if defined ZCL_KEY_ESTABLISH // Initialize the Certicom certificate information. zmain_cert_init(); #endif // Initialize basic NV items zgInit(); #ifndef NONWK // Since the AF isn't a task, call it's initialization routine afInit(); #endif // Initialize the operating system osal_init_system(); // Allow interrupts osal_int_enable( INTS_ALL ); // Final board initialization InitBoard( OB_READY ); // Display information about this device zmain_dev_info(); /* Display the device info on the LCD */ #ifdef LCD_SUPPORTED zmain_lcd_init(); #endif #ifdef WDT_IN_PM1 /* If WDT is used, this is a good place to enable it. */ WatchDogEnable( WDTIMX ); #endif osal_start_system(); // No Return from here return 0; // Shouldn't get here. } // main() /********************************************************************* * @fn zmain_vdd_check * @brief Check if the Vdd is OK to run the processor. * @return Return if Vdd is ok; otherwise, flash LED, then reset *********************************************************************/ static void zmain_vdd_check( void ) { uint8 cnt = 16; do { while (!HalAdcCheckVdd(VDD_MIN_RUN)); } while (--cnt); } /************************************************************************************************** * @fn zmain_ext_addr * * @brief Execute a prioritized search for a valid extended address and write the results * into the OSAL NV system for use by the system. Temporary address not saved to NV. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void zmain_ext_addr(void) { uint8 nullAddr[Z_EXTADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8 writeNV = TRUE; // First check whether a non-erased extended address exists in the OSAL NV. if ((SUCCESS != osal_nv_item_init(ZCD_NV_EXTADDR, Z_EXTADDR_LEN, NULL)) || (SUCCESS != osal_nv_read(ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, aExtendedAddress)) || (osal_memcmp(aExtendedAddress, nullAddr, Z_EXTADDR_LEN))) { // Attempt to read the extended address from the location on the lock bits page // where the programming tools know to reserve it. HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_IEEE_OSET, aExtendedAddress, Z_EXTADDR_LEN); if (osal_memcmp(aExtendedAddress, nullAddr, Z_EXTADDR_LEN)) { // Attempt to read the extended address from the designated location in the Info Page. if (!osal_memcmp((uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), nullAddr, Z_EXTADDR_LEN)) { osal_memcpy(aExtendedAddress, (uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), Z_EXTADDR_LEN); } else // No valid extended address was found. { uint8 idx; #if !defined ( NV_RESTORE ) writeNV = FALSE; // Make this a temporary IEEE address #endif /* Attempt to create a sufficiently random extended address for expediency. * Note: this is only valid/legal in a test environment and * must never be used for a commercial product. */ for (idx = 0; idx < (Z_EXTADDR_LEN - 2);) { uint16 randy = osal_rand(); aExtendedAddress[idx++] = LO_UINT16(randy); aExtendedAddress[idx++] = HI_UINT16(randy); } // Next-to-MSB identifies ZigBee devicetype. #if ZG_BUILD_COORDINATOR_TYPE && !ZG_BUILD_JOINING_TYPE aExtendedAddress[idx++] = 0x10; #elif ZG_BUILD_RTRONLY_TYPE aExtendedAddress[idx++] = 0x20; #else aExtendedAddress[idx++] = 0x30; #endif // MSB has historical signficance. aExtendedAddress[idx] = 0xF8; } } if (writeNV) { (void)osal_nv_write(ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, aExtendedAddress); } } // Set the MAC PIB extended address according to results from above. (void)ZMacSetReq(MAC_EXTENDED_ADDRESS, aExtendedAddress); } #if defined ZCL_KEY_ESTABLISH /************************************************************************************************** * @fn zmain_cert_init * * @brief Initialize the Certicom certificate information. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void zmain_cert_init(void) { uint8 certData[ZCL_KE_IMPLICIT_CERTIFICATE_LEN]; uint8 nullData[ZCL_KE_IMPLICIT_CERTIFICATE_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; (void)osal_nv_item_init(ZCD_NV_IMPLICIT_CERTIFICATE, ZCL_KE_IMPLICIT_CERTIFICATE_LEN, NULL); (void)osal_nv_item_init(ZCD_NV_DEVICE_PRIVATE_KEY, ZCL_KE_DEVICE_PRIVATE_KEY_LEN, NULL); // First check whether non-null certificate data exists in the OSAL NV. To save on code space, // just use the ZCD_NV_CA_PUBLIC_KEY as the bellwether for all three. if ((SUCCESS != osal_nv_item_init(ZCD_NV_CA_PUBLIC_KEY, ZCL_KE_CA_PUBLIC_KEY_LEN, NULL)) || (SUCCESS != osal_nv_read(ZCD_NV_CA_PUBLIC_KEY, 0, ZCL_KE_CA_PUBLIC_KEY_LEN, certData)) || (osal_memcmp(certData, nullData, ZCL_KE_CA_PUBLIC_KEY_LEN))) { // Attempt to read the certificate data from its corresponding location on the lock bits page. HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_CA_PUBLIC_KEY_OSET, certData, ZCL_KE_CA_PUBLIC_KEY_LEN); // If the certificate data is not NULL, use it to update the corresponding NV items. if (!osal_memcmp(certData, nullData, ZCL_KE_CA_PUBLIC_KEY_LEN)) { (void)osal_nv_write(ZCD_NV_CA_PUBLIC_KEY, 0, ZCL_KE_CA_PUBLIC_KEY_LEN, certData); HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_IMPLICIT_CERT_OSET, certData, ZCL_KE_IMPLICIT_CERTIFICATE_LEN); (void)osal_nv_write(ZCD_NV_IMPLICIT_CERTIFICATE, 0, ZCL_KE_IMPLICIT_CERTIFICATE_LEN, certData); HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_DEV_PRIVATE_KEY_OSET, certData, ZCL_KE_DEVICE_PRIVATE_KEY_LEN); (void)osal_nv_write(ZCD_NV_DEVICE_PRIVATE_KEY, 0, ZCL_KE_DEVICE_PRIVATE_KEY_LEN, certData); } } } #endif /************************************************************************************************** * @fn zmain_dev_info * * @brief This displays the IEEE (MSB to LSB) on the LCD. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void zmain_dev_info(void) { #ifdef LCD_SUPPORTED uint8 i; uint8 *xad; uint8 lcd_buf[Z_EXTADDR_LEN*2+1]; // Display the extended address. xad = aExtendedAddress + Z_EXTADDR_LEN - 1; for (i = 0; i < Z_EXTADDR_LEN*2; xad--) { uint8 ch; ch = (*xad >> 4) & 0x0F; lcd_buf[i++] = ch + (( ch < 10 ) ? '0' : '7'); ch = *xad & 0x0F; lcd_buf[i++] = ch + (( ch < 10 ) ? '0' : '7'); } lcd_buf[Z_EXTADDR_LEN*2] = '\0'; HalLcdWriteString( "IEEE: ", HAL_LCD_LINE_1 ); HalLcdWriteString( (char*)lcd_buf, HAL_LCD_LINE_2 ); #endif } #ifdef LCD_SUPPORTED /********************************************************************* * @fn zmain_lcd_init * @brief Initialize LCD at start up. * @return none *********************************************************************/ static void zmain_lcd_init ( void ) { #ifdef SERIAL_DEBUG_SUPPORTED { HalLcdWriteString( "TexasInstruments", HAL_LCD_LINE_1 ); #if defined( MT_MAC_FUNC ) #if defined( ZDO_COORDINATOR ) HalLcdWriteString( "MAC-MT Coord", HAL_LCD_LINE_2 ); #else HalLcdWriteString( "MAC-MT Device", HAL_LCD_LINE_2 ); #endif // ZDO #elif defined( MT_NWK_FUNC ) #if defined( ZDO_COORDINATOR ) HalLcdWriteString( "NWK Coordinator", HAL_LCD_LINE_2 ); #else HalLcdWriteString( "NWK Device", HAL_LCD_LINE_2 ); #endif // ZDO #endif // MT_FUNC } #endif // SERIAL_DEBUG_SUPPORTED } #endif /********************************************************************* *********************************************************************/ 以上是DHT11代码,请帮我生成一个光敏代码
最新发布
06-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值