16进制字节数据就是一个字节数组,把modbus命令存放在一个字节数组中,发送即可。
也可以先用流行支持协议的串口软件,如格西烽火等,编写好协议,测试通过再把命令字节数组在单片机中实现。
串口只接收字符
要输出16进制形式
那么需要在代码中
先将字符串转为16进制形式的字符串
再写到串口。
#include"usart1.h"#include stdarg.h
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
//配置输出TX引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, GPIO_InitStructure);
//配置输入RX引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位1位
USART_InitStructure.USART_Parity = USART_Parity_No ; //无奇偶校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
/* * 函数名:itoa
* 描述 :将整形数据转换成字符串
* 输入 :-radix =10 表示10进制,其他结果为0
* -value 要转换的整形数
* -buf 转换后的字符串
* -radix = 10
* 输出 :无
* 返回 :无
* 调用 :被USART1_printf()调用
*/
static char *itoa(int value, char *string, int radix)
{
int i, d;
int flag = 0;
char *ptr = string;
/* This implementation only works for decimal numbers. */ if (radix != 10)
{
*ptr = 0;
return string;
}
if (!value) {
*ptr++ = 0x30;
*ptr = 0;
return string;
}
/* if this is a negative value insert the minus sign. */ if (value 0)
{
*ptr++ = '-';
/* Make the value positive. */ value *= -1;
}
for (i = 10000; i 0; i /= 10) {
d = value / i;
if (d || flag) {
*ptr++ = (char)(d + 0x30);
value -= (d * i);
flag = 1;
}
}
/* Null terminate the string. */ *ptr = 0;
return string;
} /* NCL_Itoa */
/* * 函数名:USART1_printf
* 描述 :格式化输出,类似于C库中的printf,但这里没有用到C库
* 输入 :-USARTx 串口通道,这里只用到了串口1,即USART1
* -Data 要发送到串口的内容的指针
* -... 其他参数
* 输出 :无
* 返回 :无
* 调用 :外部调用
* 典型应用USART1_printf( USART1, "\r\n this is a demo \r\n" );
* USART1_printf( USART1, "\r\n %d \r\n", i );
* USART1_printf( USART1, "\r\n %s \r\n", j );
*/
int USART1_printf(USART_TypeDef* USARTx, uint8_t *Data,...)
{
const char *s;
int d;
char buf[16];
va_list ap; va_start(ap, Data);
while ( *Data != 0) // 判断是否到达字符串结束符 {
if ( *Data == 0x5c ) //'\'
{
switch ( *++Data )
{
case 'r': //回车符
USART_SendData(USARTx, 0x0d);
Data ++;
break;
case 'n': //换行符 USART_SendData(USARTx, 0x0a);
Data ++;
break;
default:
Data ++;
break;
}
}
else if ( *Data == '%')
{ //
switch ( *++Data )
{
case 's': //字符串
s = va_arg(ap, const char *);
for ( ; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
Data++;
break;
case 'd': //十进制 d = va_arg(ap, int);
itoa(d, buf, 10);
for (s = buf; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
Data++;
break;
default:
Data++;
break;
}
} /* end of else if */
else USART_SendData(USARTx, *Data++);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
}
/*
* 函数名:fputc
* 描述 :重定向c库函数printf到USART1
* 输入 :无
* 输出 :无
* 调用 :由printf调用
*/
int fputc(int ch, FILE *f)
{
/* 将Printf内容发往串口 */
USART_SendData(USART1, (unsigned char) ch);
while (!(USART1-SR USART_FLAG_TXE));
return (ch);
}
receivedata的返回值应该不是你想的0x0403这样的格式。在做If判断前,让输出或跟踪一下该返回值到底是什么。
监视代码运行过程的中间值,是调试程序能力中最基础的技能。必竟不能奢望代码输入后第一次运行就能一切正常。
串口一般只能接受8位的数据,也就是按字节进行传输,要是数据超过1个字节的和数据,你就需要建立协议来进行数据重组。这就涉及到大小端问题(你是先发送高8位还是低8位),断帧问题(可通过添加特定字符组成的帧头帧尾来识别,或者通过时间间隔来识别)。
简单的介绍一下操作方法,每接收一个字节数据,你就在串口中断函数里面把数据取出来放到一个足够长的数组中去,记得依次往后增加地址。
接着你可以通过以上提到的两种方式断帧,判定为此次收到一帧数据后,重组数据并处理数据,接着清空上面的数组,好让后面收到的数据有空间放进去,以此不断循环即可实现协议通讯。
本文标签:stm32网口字符串转16进制串口