自己创建简单的mcu中常用的库函数

文章目录

  • 自己创建简单的mcu中常用的库函数
  • 1. 自己编写库函数的意义
  • 2. 计算字符串长度.以'\0'作为结束符
  • 3. 复制字符串
  • 4. 字符串比较
  • 5. 将整数转换为ASCII数组
  • 6. 将ASCII码字符串转换成整数
  • 7. 将字节数组转换为16位整数
  • 8.计算CRC,用于Modbus协议
  • 9. 根据直线方程上的两点,给X计算第三个点的Y值
  • 10. 将BCD码转为ASCII字符
  • 11.将二进制数组转换为16进制格式的ASCII字符串
  • 12. 变长的 ASCII 字符转换为32位整数

  • 声明:这些函数大部分是我在安富莱电子的教程上面抄下来的,硬汉哥写过很多优秀的教程,大家可以去学习学习,论坛链接。有的是我从别处摘抄来的,这篇文章我会一直补充。

    1. 自己编写库函数的意义

    但我们在使用c语言写mcu程序的时候,有的时候需要使用库函数,当然我们可以使用标准的库函数,如stdio库用于输入输出

    string库用于字符串操作等,但是标准的库实在是太大了,对于mcu很不友好,因此mcu往往会使用其它的一些c库,如keil提供了MicroLIB库,还有其它的如newlib等库,这些库虽然比标准库小的多,但是有时候还是太大了,因此我们就需要封装一些常用的库,来减少c库的引入。

    2. 计算字符串长度.以’\0’作为结束符

    /*
    *********************************************************************************************************
    *	函 数 名: str_len
    *	功能说明: 计算字符串长度.以'\0'作为结束符
    *	形    参: _str : 缓冲区
    *	返 回 值: 无
    *********************************************************************************************************
    */
    int str_len(char *_str)
    {
    	int len = 0;
    
    	while (*_str++) len++;
    	return len;
    }
    

    3. 复制字符串

    /*
    *********************************************************************************************************
    *	函 数 名: str_cpy
    *	功能说明: 复制字符串
    *	形    参: tar : 目标缓冲区
    *			 src : 源缓冲区
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void str_cpy(char *_tar, char *_src)
    {
    	do
    	{
    		*_tar++ = *_src;
    	}
    	while (*_src++);
    }
    
    /*
    *********************************************************************************************************
    *	函 数 名: str_copy
    *	功能说明: 复制字符串
    *	形    参: tar : 目标缓冲区
    *			 src : 源缓冲区
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void mem_set(char *_tar, char _data, int _len)
    {
    	while (_len--)
    	{
    		*_tar++ = _data;
    	}
    }
    

    4. 字符串比较

    /*
    *********************************************************************************************************
    *	函 数 名: str_cmp
    *	功能说明: 字符串比较
    *	形    参: s1 : 字符串1
    *			  s2 : 字符串2
    *	返 回 值: 0 表示相等 非0表示不等
    *********************************************************************************************************
    */
    int str_cmp(char * s1, char * s2)
    {
    	while ((*s1!=0) && (*s2!=0) && (*s1==*s2))
    	{
    		s1++;
    		s2++;
    	}
    	return *s1 - *s2;
    }
    

    5. 将整数转换为ASCII数组

    /*
    *********************************************************************************************************
    *	函 数 名: int_to_ascii
    *	功能说明: 将整数转换为ASCII数组。支持负数。
    *	形    参: _Number : 整数
    *			 _pBuf : 目标缓冲区, 存放转换后的结果。以0结束的字符串。
    *			 _len : ASCII字符个数, 字符串长度
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void int_to_str(int _iNumber, char *_pBuf, unsigned char _len)
    {
    	unsigned char i;
    	int iTemp;
    
    	if (_iNumber < 0)	/* 负数 */
    	{
    		iTemp = -_iNumber;	/* 转为正数 */
    	}
    	else
    	{
    		iTemp = _iNumber;
    	}
    
    	mem_set(_pBuf, ' ',_len);
    
    	/* 将整数转换为ASCII字符串 */
    	for (i = 0; i < _len; i++)
    	{
    		_pBuf[_len - 1 - i] = (iTemp % 10) + '0';
    		iTemp = iTemp / 10;
    		if (iTemp == 0)
    		{
    			break;
    		}
    	}
    	_pBuf[_len] = 0;
    
    	if (_iNumber < 0)	/* 负数 */
    	{
    		for (i = 0; i < _len; i++)
    		{
    			if ((_pBuf[i] == ' ') && (_pBuf[i + 1] != ' '))
    			{
    				_pBuf[i] = '-';
    				break;
    			}
    		}
    	}
    }
    

    6. 将ASCII码字符串转换成整数

    /*
    *********************************************************************************************************
    *	函 数 名: str_to_int
    *	功能说明: 将ASCII码字符串转换成整数。 遇到小数点自动越过。
    *	形    参: _pStr :待转换的ASCII码串. 可以以逗号,#或0结束。 2014-06-20 修改为非0-9的字符。
    *	返 回 值: 二进制整数值
    *********************************************************************************************************
    */
    int str_to_int(char *_pStr)
    {
    	unsigned char flag;
    	char *p;
    	int ulInt;
    	unsigned char  i;
    	unsigned char  ucTemp;
    
    	p = _pStr;
    	if (*p == '-')
    	{
    		flag = 1;	/* 负数 */
    		p++;
    	}
    	else
    	{
    		flag = 0;
    	}
    
    	ulInt = 0;
    	for (i = 0; i < 15; i++)
    	{
    		ucTemp = *p;
    		if (ucTemp == '.')	/* 遇到小数点,自动跳过1个字节 */
    		{
    			p++;
    			ucTemp = *p;
    		}
    		if ((ucTemp >= '0') && (ucTemp <= '9'))
    		{
    			ulInt = ulInt * 10 + (ucTemp - '0');
    			p++;
    		}
    		else
    		{
    			break;
    		}
    	}
    
    	if (flag == 1)
    	{
    		return -ulInt;
    	}
    	return ulInt;
    }
    

    7. 将字节数组转换为16位整数

    /*
    *********************************************************************************************************
    *	函 数 名: BEBufToUint16
    *	功能说明: 将2字节数组(大端Big Endian次序,高字节在前)转换为16位整数
    *	形    参: _pBuf : 数组
    *	返 回 值: 16位整数值
    *
    *   大端(Big Endian)与小端(Little Endian)
    *********************************************************************************************************
    */
    uint16_t BEBufToUint16(uint8_t *_pBuf)
    {
        return (((uint16_t)_pBuf[0] << 8) | _pBuf[1]);
    }
    
    /*
    *********************************************************************************************************
    *	函 数 名: LEBufToUint16
    *	功能说明: 将2字节数组(小端Little Endian,低字节在前)转换为16位整数
    *	形    参: _pBuf : 数组
    *	返 回 值: 16位整数值
    *********************************************************************************************************
    */
    uint16_t LEBufToUint16(uint8_t *_pBuf)
    {
        return (((uint16_t)_pBuf[1] << 8) | _pBuf[0]);
    }
    
    /*
    *********************************************************************************************************
    *	函 数 名: BEBufToUint32
    *	功能说明: 将4字节数组(大端Big Endian次序,高字节在前)转换为16位整数
    *	形    参: _pBuf : 数组
    *	返 回 值: 16位整数值
    *
    *   大端(Big Endian)与小端(Little Endian)
    *********************************************************************************************************
    */
    uint32_t BEBufToUint32(uint8_t *_pBuf)
    {
        return (((uint32_t)_pBuf[0] << 24) | ((uint32_t)_pBuf[1] << 16) | ((uint32_t)_pBuf[2] << 8) | _pBuf[3]);
    }
    
    /*
    *********************************************************************************************************
    *	函 数 名: LEBufToUint32
    *	功能说明: 将4字节数组(小端Little Endian,低字节在前)转换为16位整数
    *	形    参: _pBuf : 数组
    *	返 回 值: 16位整数值
    *********************************************************************************************************
    */
    uint32_t LEBufToUint32(uint8_t *_pBuf)
    {
        return (((uint32_t)_pBuf[3] << 24) | ((uint32_t)_pBuf[2] << 16) | ((uint32_t)_pBuf[1] << 8) | _pBuf[0]);
    }
    

    8.计算CRC,用于Modbus协议

    采用查表法,空间换时间

    // CRC 高位字节值表
    static const uint8_t s_CRCHi[] = {
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
    } ;
    // CRC 低位字节值表
    const uint8_t s_CRCLo[] = {
    	0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
    	0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
    	0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
    	0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
    	0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
    	0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    	0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
    	0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
    	0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
    	0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
    	0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
    	0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    	0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
    	0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
    	0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
    	0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
    	0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
    	0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    	0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
    	0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
    	0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
    	0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
    	0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
    	0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    	0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
    	0x43, 0x83, 0x41, 0x81, 0x80, 0x40
    };
    
    /*
    *********************************************************************************************************
    *	函 数 名: CRC16_Modbus
    *	功能说明: 采用查表法计算CRC。 用于Modbus协议。
    *	形    参: _pBuf : 参与校验的数据
    *			  _usLen : 数据长度
    *	返 回 值: 16位整数值。 对于Modbus ,此结果高字节先传送,低字节后传送。
    *
    *   所有可能的CRC值都被预装在两个数组当中,当计算报文内容时可以简单的索引即可;
    *   一个数组包含有16位CRC域的所有256个可能的高位字节,另一个数组含有低位字节的值;
    *   这种索引访问CRC的方式提供了比对报文缓冲区的每一个新字符都计算新的CRC更快的方法;
    *
    *  注意:此程序内部执行高/低CRC字节的交换。此函数返回的是已经经过交换的CRC值;也就是说,该函数的返回值可以直接放置
    *        于报文用于发送;
    *********************************************************************************************************
    */
    uint16_t CRC16_Modbus(uint8_t *_pBuf, uint16_t _usLen)
    {
    	uint8_t ucCRCHi = 0xFF; /* 高CRC字节初始化 */
    	uint8_t ucCRCLo = 0xFF; /* 低CRC 字节初始化 */
    	uint16_t usIndex;  /* CRC循环中的索引 */
    
        while (_usLen--)
        {
    		usIndex = ucCRCHi ^ *_pBuf++; /* 计算CRC */
    		ucCRCHi = ucCRCLo ^ s_CRCHi[usIndex];
    		ucCRCLo = s_CRCLo[usIndex];
        }
        return ((uint16_t)ucCRCHi << 8 | ucCRCLo);
    }
    

    采用计算的方法来计算crc16,时间换空间

    /*
    *********************************************************************************************************
    *	函 数 名: modbus_crc16
    *	功能说明: 采用计算法计算CRC。 用于Modbus协议。
    *	形    参: data : 参与校验的数据
    *			 length : 数据长度
    *	返 回 值: 16位整数值。 对于Modbus ,此结果高字节先传送,低字节后传送。
    *********************************************************************************************************
    */
    uint16_t modbus_crc16(uint16_t length, uint8_t *data)
    {
        uint16_t crc = 0xffff;
        bool t = 0;
        uint16_t R = 0xa001;
        while(length){
            crc = crc ^ *data++;
            for(int a=0; a<8; ){
                t = crc % 2;
                crc = crc / 2;
                a++;
                if(t == 1){
                    crc = crc ^ R;
                } 
            }c
            length--;
        }
        return crc;
    }
    

    9. 根据直线方程上的两点,给X计算第三个点的Y值

    /*
    *********************************************************************************************************
    *	函 数 名: CaculTwoPoint
    *	功能说明: 根据2点直线方程,计算Y值
    *	形    参:  2个点的坐标和x输入量
    *	返 回 值: x对应的y值
    *********************************************************************************************************
    */
    int32_t  CaculTwoPoint(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x)
    {
    	return y1 + ((int64_t)(y2 - y1) * (x - x1)) / (x2 - x1);
    }
    

    10. 将BCD码转为ASCII字符

    /*
    *********************************************************************************************************
    *	函 数 名: BcdToChar
    *	功能说明: 将BCD码转为ASCII字符。 比如 0x0A ==> 'A'
    *	形    参: _bcd   :输入的二进制数。必须小于16
    *	返 回 值: 转换结果
    *********************************************************************************************************
    */
    char BcdToChar(uint8_t _bcd)
    {
    	if (_bcd < 10)
    	{
    		return _bcd + '0';
    	}
    	else if (_bcd < 16)
    	{
    		return _bcd + 'A';
    	}
    	else
    	{
    		return 0;
    	}
    }
    

    11.将二进制数组转换为16进制格式的ASCII字符串

    /*
    *********************************************************************************************************
    *	函 数 名: HexToAscll
    *	功能说明: 将二进制数组转换为16进制格式的ASCII字符串。每个2个ASCII字符后保留1个空格。
    *			  0x12 0x34 转化为 0x31 0x32 0x20 0x33 0x34 0x00  即 "1234"
    *	形    参: 	_pHex   :输入的数据,二进制数组
    *				_pAscii :存放转换结果, ASCII字符串,0结束。1个二进制对应2个ASCII字符.
    *	返 回 值: 转换得到的整数
    *********************************************************************************************************
    */
    void HexToAscll(uint8_t * _pHex, char *_pAscii, uint16_t _BinBytes)
    {
    	uint16_t i;
    	
    	if (_BinBytes == 0)
    	{
    		_pAscii[0] = 0;
    	}
    	else
    	{
    		for (i = 0; i < _BinBytes; i++)
    		{
    			_pAscii[3 * i] = BcdToChar(_pHex[i] >> 4);
    			_pAscii[3 * i + 1] = BcdToChar(_pHex[i] & 0x0F);
    			_pAscii[3 * i + 2] = ' ';
    		}
    		_pAscii[3 * (i - 1) + 2] = 0;
    	}
    }
    

    12. 变长的 ASCII 字符转换为32位整数

    /*
    *********************************************************************************************************
    *	函 数 名: AsciiToUint32
    *	功能说明: 变长的 ASCII 字符转换为32位整数  ASCII 字符以空格或者0结束 。 支持16进制和10进制输入
    *	形    参: *pAscii :要转换的ASCII码
    *	返 回 值: 转换得到的整数
    *********************************************************************************************************
    */
    uint32_t AsciiToUint32(char *pAscii)
    {
    	char i;
    	char bTemp;
    	char bIsHex;
    	char bLen;
    	char bZeroLen;
    	uint32_t lResult;
    	uint32_t lBitValue;
    
    	/* 判断是否是16进制数 */
    	bIsHex = 0;
    	if ((pAscii[0] == '0') && ((pAscii[1] == 'x') || (pAscii[1] == 'X')))
    	{
    		bIsHex=1;
    	}
    
    	lResult=0;
    	// 最大数值为 4294967295, 10位+2字符"0x" //
    	if (bIsHex == 0)
    	{ // 十进制 //
    		// 求长度 //
    		lBitValue=1;
    
    		/* 前导去0 */
    		for (i = 0; i < 8; i++)
    		{
    			bTemp = pAscii[i];
    			if (bTemp != '0')
    				break;
    		}
    		bZeroLen = i;
    
    		for (i = 0; i < 10; i++)
    		{
    			if ((pAscii[i] < '0') || (pAscii[i] > '9'))
    				break;
    			lBitValue = lBitValue * 10;
    		}
    		bLen = i;
    		lBitValue = lBitValue / 10;
    		if (lBitValue == 0)
    			lBitValue=1;
    		for (i = bZeroLen; i < bLen; i++)
    		{
    			lResult += (pAscii[i] - '0') * lBitValue;
    			lBitValue /= 10;
    		}
    	}
    	else
    	{	/* 16进制 */
    		/* 求长度 */
    		lBitValue=1;
    
    		/* 前导去0 */
    		for (i = 0; i < 8; i++)
    		{
    			bTemp = pAscii[i + 2];
    			if(bTemp!='0')
    				break;
    		}
    		bZeroLen = i;
    		for (; i < 8; i++)
    		{
    			bTemp=pAscii[i+2];
    			if (((bTemp >= 'A') && (bTemp <= 'F')) ||
    				((bTemp>='a')&&(bTemp<='f')) ||
    				((bTemp>='0')&&(bTemp<='9')) )
    			{
    				lBitValue=lBitValue * 16;
    			}
    			else
    			{
    				break;
    			}
    		}
    		lBitValue = lBitValue / 16;
    		if (lBitValue == 0)
    			lBitValue = 1;
    		bLen = i;
    		for (i = bZeroLen; i < bLen; i++)
    		{
    			bTemp = pAscii[i + 2];
    			if ((bTemp >= 'A') && (bTemp <= 'F'))
    			{
    				bTemp -= 0x37;
    			}
    			else if ((bTemp >= 'a') && (bTemp <= 'f'))
    			{
    				bTemp -= 0x57;
    			}
    			else if ((bTemp >= '0') && (bTemp <= '9'))
    			{
    				bTemp -= '0';
    			}
    			lResult += bTemp*lBitValue;
    			lBitValue /= 16;
    		}
    	}
    	return lResult;
    }
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » 常用的嵌入式库函数

    发表评论