C语言变成实现串口收发数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言变成实现串口收发数据相关的知识,希望对你有一定的参考价值。

不需要实现什么复杂的功能,最近初学串口,求一段VS或者VC6.0编写的C语言程序,能够实现串口数据的收发,最好每行都有必要的注释,方便吾等菜鸟学习,多谢各位,有现成的程序麻烦发一份。

#include <reg51.h>

#include <intrins.h>

unsigned char key_s, key_v, tmp;

char code str[] = "welcome! www.willar.com \\n\\r";

void send_str();

bit scan_key();

void proc_key();

void delayms(unsigned char ms);

void send_char(unsigned char txd);

sbit K1 = P1^4;

main()

TMOD = 0x20; // 定时器1工作于8位自动重载模式, 用于产生波特率

TH1 = 0xFD; // 波特率9600

TL1 = 0xFD;

SCON = 0x50; // 设定串行口工作方式

PCON &= 0xef; // 波特率不倍增

TR1 = 1; // 启动定时器1

IE = 0x0; // 禁止任何中断

while(1)

if(scan_key()) // 扫描按键

delayms(10); // 延时去抖动

if(scan_key()) // 再次扫描

key_v = key_s; // 保存键值

proc_key(); // 键处理

if(RI) // 是否有数据到来

RI = 0;

tmp = SBUF; // 暂存接收到的数据

P0 = tmp; // 数据传送到P0口

send_char(tmp); // 回传接收到的数据



bit scan_key()

// 扫描按键

key_s = 0x00;

key_s |= K1;

return(key_s ^ key_v);



void proc_key()

// 键处理

if((key_v & 0x01) == 0)

// K1按下

send_str(); // 传送字串"welcome!...



void send_char(unsigned char txd)

// 传送一个字符

SBUF = txd;

while(!TI); // 等特数据传送


TI = 0; // 清除数据传送标志



void send_str()

// 传送字串

unsigned char i = 0;

while(str[i] != '\\0')

SBUF = str[i];

while(!TI); // 等特数据传送

TI = 0; // 清除数据传送标志

i++; // 下一个字符

void delayms(unsigned char ms)

// 延时子程序

unsigned char i;

while(ms--)

for(i = 0; i < 120; i++);

拓展资料

C语言是一门通用计算机编程语言,应用广泛。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。

二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。



参考技术A

首先是把数据发送出去,发送数据协议是自己定义的,一个数据头2个字节,20个字节数据位,2个字节CRC校验位,每个数据共24字节的数据。

temp = temp ^ 0x11021


if ((*ptr & i) != 0)


temp = temp ^ (0x10000 ^ 0x11021);



ptr++;



crc = temp;


memcpy(result + 5 * len + 3 * len1, &crc, len1);



DWORD dwwrittenLen = 0;


if (!WriteFile(hCom, result, 24, &dwwrittenLen, NULL))



printf("发送数据失败!\\n");



printf("Main Baseline往串口发送数据成功!");



/***********关闭串口***********/


CloseHandle(hCom);

数据发送成功,主要是接收的程序调试了很久,一开始也是打算一个数据24个字节24个字节来循环接收,但是每组数据会在固定的第10-13个字节出错。

//设定读超时


TimeOuts.ReadIntervalTimeout = 1000;


TimeOuts.ReadTotalTimeoutMultiplier = 500;


TimeOuts.ReadTotalTimeoutConstant = 5000;


//设定写超时


TimeOuts.WriteTotalTimeoutMultiplier = 500;


TimeOuts.WriteTotalTimeoutConstant = 2000;


SetCommTimeouts(hCom1, &TimeOuts);//设置超时


DCB dcb1;


GetCommState(hCom1, &dcb1);


dcb1.BaudRate = 115200;//波特率为9600


dcb1.ByteSize = 8;//每个字节有8位


dcb1.Parity = NOPARITY;//无奇偶校验位


dcb1.StopBits = TWOSTOPBITS;//两个停止位


//dcb1.fParity = FALSE;


//dcb1.fNull = FALSE;


SetCommState(hCom1, &dcb1);


DWORD wCount=8;//读取的字节数

fclose(fp1);



CloseHandle(hCom1);


最后 就是将发送的数据和接收的数据放到TXT文件里进行了比对,完全没有问题。

参考技术B 以下是我刚改的程序编译成功了
请参考

#include"reg51.h"
//定义全局变量
unsigned char data_10[10]=0,0,0,0,0,0,0,0,0,0;
unsigned char Time_50ms,count;
bit flag=0;
bit data_flag=0;
/*********************************************************************************************
函数名:UART串口初始化函数
调 用:UART_init();
参 数:无
返回值:无
结 果:启动UART串口接收中断,允许串口接收,启动T/C1产生波特率(占用)
备 注:振荡晶体为12MHz,PC串口端设置 [ 4800,8,无,1,无 ]
/**********************************************************************************************/
void UART_init (void)
EA = 1; //允许总中断(如不使用中断,可用//屏蔽)
ES = 1; //允许UART串口的中断
TMOD |= 0x20;//定时器T/C1工作方式2
SCON = 0x50;//串口工作方式1,允许串口接收(SCON = 0x40 时禁止串口接收)
TH1 = 0xF3;//定时器初值高8位设置
TL1 = 0xF3;//定时器初值低8位设置
PCON = 0x80;//波特率倍频(屏蔽本句波特率为2400)
TR1 = 1;//定时器启动

/**********************************************************************************************/
/*********************************************************************************************
函数名:UART串口接收中断处理函数
调 用:[SBUF收到数据后中断处理]
参 数:无
返回值:无
结 果:UART串口接收到数据时产生中断,用户对数据进行处理(并发送回去)
备 注:过长的处理程序会影响后面数据的接收
/**********************************************************************************************/
void UART_R (void) interrupt 4 using 1 //切换寄存器组到1
TR0=1; //打开定时器开始计时
RI = 0;//令接收中断标志位为0(软件清零)
data_10[count] = SBUF;//将接收到的数据送入变量 UART_data
count++;//接收到一个字节数据计数+1
if(count>=10) //如果接收到10个数据

TR0=0; //停止定时器
TH0 = 0x3C; //给定时器赋初值
TL0 = 0xB0; //给定时器赋初值
count=0;//清零数据计数
//data_flag=1; //数据有效标志位
SBUF = 0x55;//返回数据 55H
while(TI == 0);//检查发送中断标志位
TI = 0;//令发送中断标志位为0(软件清零)

if(flag)

TR0=0; //停止定时器
TH0 = 0x3C; //给定时器赋初值
TL0 = 0xB0; //给定时器赋初值
count=0;//清零数据计数
SBUF = 0xff;//返回数据 ffH
while(TI == 0);//检查发送中断标志位
TI = 0;//令发送中断标志位为0(软件清零)


/**********************************************************************************************/
/*********************************************************************************************
函数名:定时/计数器初始化函数
调 用:T_C_init();
参 数:无
返回值:无
结 果:设置SFR中T/C1和(或)T/C0相关参数
备 注:本函数控制T/C1和T/C0,不需要使用的部分可用//屏蔽
/**********************************************************************************************/
void T_C_init (void)
TMOD |= 0x01; //高4位控制T/C1 [ GATE,C/T,M1,M0,GATE,C/T,M1,M0 ]
EA = 1;//中断总开关
TH0 = 0x3C; //16位计数寄存器T0高8位
TL0 = 0xB0; //16位计数寄存器T0低8位(0x3CB0 = 50mS延时)
ET0 = 1; //T/C0中断开关
TR0 = 0; //T/C0开关

/**********************************************************************************************/
/*********************************************************************************************
函数名:定时/计数器0中断处理函数
调 用:[T/C0溢出后中断处理]
参 数:无
返回值:无
结 果:重新写入16位计数寄存器初始值,处理用户程序
备 注:必须允许中断并启动T/C本函数方可有效,重新写入初值需和T_C_init函数一致
/**********************************************************************************************/
void T_C0 (void) interrupt 1 using 1 //切换寄存器组到1
TH0 = 0x3C; //16位计数寄存器T0高8位(重新写入初值)
TL0 = 0xB0; //16位计数寄存器T0低8位(0x3CB0 = 50mS延时)
Time_50ms++; //50ms到 计数+1
if(Time_50ms>=100)

Time_50ms=0;// 清零50ms计数
flag=1; //5s时间 标志置位
TR0=0;//关闭计时器


/**********************************************************************************************/
main()

IP = 0x10; //中断优先级设置(串口中断最高优先级)
UART_init();//初始化串口
T_C_init(); // 初始化计数器
while(1);// 空循环

希望能解决您的问题。
参考技术C #include <stdio.h>
#include <Windows.h>
int main(void)

FILE *fp;
char temp;
char buf[100];
if((fp = fopen("com3","r")) == NULL)
puts("this way doesn't work!\\n");
else
puts("this way works!\\n");
while(1)

temp = 0;
fscanf(fp,"%c",&temp);
if(temp != 0)
putchar(temp);
else
Sleep(100);

fclose(fp);
return 0;

以前弄的,好久没看了,不知到对不对。

还有下面这段:

#include <Windows.h>
#include <stdio.h>
HANDLE hCom;
int main(void)

hCom=CreateFile(TEXT("COM3"),//COM1口
GENERIC_READ|GENERIC_WRITE, //允许读和写
0, //独占方式
NULL,
OPEN_EXISTING, //打开而不是创建
0, //同步方式
NULL);
if(hCom==(HANDLE)-1)

printf("打开COM失败!\\n");
return FALSE;

else

printf("COM打开成功!\\n");

SetupComm(hCom,1024,1024); //输入缓冲区和输出缓冲区的大小都是1024
COMMTIMEOUTS TimeOuts;
//设定读超时
TimeOuts.ReadIntervalTimeout=1000;
TimeOuts.ReadTotalTimeoutMultiplier=500;
TimeOuts.ReadTotalTimeoutConstant=5000;
//设定写超时
TimeOuts.WriteTotalTimeoutMultiplier=500;
TimeOuts.WriteTotalTimeoutConstant=2000;
SetCommTimeouts(hCom,&TimeOuts); //设置超时
DCB dcb;
GetCommState(hCom,&dcb);
dcb.BaudRate=9600; //波特率为9600
dcb.ByteSize=8; //每个字节有8位
dcb.Parity=NOPARITY; //无奇偶校验位
dcb.StopBits=ONE5STOPBITS; //两个停止位
SetCommState(hCom,&dcb);
DWORD wCount;//读取的字节数
BOOL bReadStat;
while(1)

PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR); //清空缓冲区
char str[9]=0;
printf("%s\\n",str);
bReadStat=ReadFile(hCom,str,9,&wCount,NULL);
if(!bReadStat)

printf("读串口失败!");
return FALSE;

else

str[8]='\\0';
printf("%s\\n",str);

Sleep(100);



以上两段代码是一年前弄的,我记得可以用,你试试。

本回答被提问者采纳
参考技术D 楼上那位发的是单片机的c语言编程吧?楼主想要单片机的吗?追问

我想要的是VS编的串口数据收发的程序,不是单片机的,我现在没有单片机的板子测试,只有两根USB转串口的线,所以想用VS的程序测试一下,现在正在用的是vs2005,帮忙发一份吧

STM32学习笔记 二基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发

系列文章目录

一、基于STM32F103C8T6最小系统板和STM32CubeMX实现LED灯循环闪烁
二、基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发
三、实战小例程 基于STM32F103C8T6最小系统板和STM32CubeMX驱动WS2812B光立方
四、基于STM32F103C8T6最小系统板HAL库CubeMX驱动HC-SR501红外人体传感模块
五、基于STM32F103C8T6(HAL库)的HC-SR501红外人体传感及HC-SR04超声波测距


文章目录


前言

这次我用的板子是一个用STM32F103C8T6作为主控芯片的一个数据采集卡,两个LED灯连接的引脚是PB3与PB4,TX与RX引脚分别是PA9和PA10。

完整工程下载链接:
基于STM32F103C8T6(HAL库)和CubeMX实现UART串口通信数据收发.rar

相关基础概念:
基于STM32之UART串口通信协议(一)详解



一、配置CubeMX

1、新建工程;
2、配置时钟源,在RCC里面的HSE配置的是晶振时钟;
3、配置程序烧录引脚SYS为SWD模式;
4、配置GPIO口,配置一个LED灯(我的板子是PB3),起到串口成功接收到数据时的指示作用;
5、配置串口收发引脚

此处我们采用的通信方式为UART通信(异步全双工串口通信),PA9作为TX,PA10作为RX使用。直接在可视框图里点击相应的引脚进行配置。

配置到目前,效果图为:

可以发现,TX和RX两个引脚配置完之后是黄色的,代表还没有配置完毕,下面继续进行配置。

6、在左边的"Connectivity”里面的USART1模式里选择异步全双工通信模式asynchronous
⮚点击USATR1
⮚设置MODE为异步通信(Asynchronous)
⮚基础参数:波特率为115200 Bits/s。传输数据长度为8 Bit。奇偶检验无,停止位1,接收和发送都使能
⮚GPIO引脚设置 USART1_RX/USART_TX
⮚NVIC Settings 一栏使能接收中断

这里简单扩展一下:
STM32F103系列单片机共有5个串口,其中1-3是通用同步/异步串行接口USART(Universal Synchronous/Asynchronous Receiver/Transmitter),4,、5是通用异步串行接口UART(Universal Asynchronous Receiver/Transmitter)。


7、配置时钟树,我还是开到最高的72MHz
8、进行项目设置,最后生成代码,CubeMX部分就大功告成了

二、HAL库UART相关函数简介

2.1 串口发送/接收函数

HAL_UART_Transmit();//串口发送数据,使用超时管理机制 
HAL_UART_Receive();//串口接收数据,使用超时管理机制
HAL_UART_Transmit_IT();//串口中断模式发送  
HAL_UART_Receive_IT();//串口中断模式接收
HAL_UART_Transmit_DMA();//串口DMA模式发送
HAL_UART_Transmit_DMA();//串口DMA模式接收

这六个函数参数基本一致,发送/接收各挑一个常用的函数进行简单介绍:

串口发送数据:

HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

功能:

串口发送指定长度的数据。如果超时没发送完成,则不再发送,返回超时标志(HAL_TIMEOUT)。

参数

⮚ UART_HandleTypeDef *huart UART的别名 如 : UART_HandleTypeDef huart1; 别名就是huart1
⮚ *pData 需要发送的数据
⮚ Size 发送的字节数
⮚ Timeout 最大发送时间,发送数据超过该时间退出发送
举例: HAL_UART_Transmit(&huart1, (uint8_t *)ZZX, 3, 0xffff); //串口发送三个字节数据,最大传输时间0xffff


串口接收数据:

HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

功能:

串口中断接收,以中断方式接收指定长度数据。
大致过程是,设置数据存放位置,接收数据长度,然后使能串口接收中断。接收到数据时,会触发串口中断。再然后,串口中断函数处理,直到接收到指定长度数据,而后关闭中断,进入中断接收回调函数,不再触发接收中断。(只触发一次中断)

参数

⮚ UART_HandleTypeDef *huart UART的别名
⮚ *pData 接收到的数据存放地址
⮚ Size 接收的字节数
举例: HAL_UART_Receive_IT(&huart1,(uint8_t *)&value,1); //中断接收一个字符,存储到value中

2.2 串口中断函数

HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  //串口中断处理函数
HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);  //串口发送中断回调函数
HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);  //串口发送一半中断回调函数(不常用)
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  //串口接收中断回调函数
HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数(不常用)
HAL_UART_ErrorCallback();//串口接收错误函数

串口接收中断回调函数:

HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  

功能:

HAL库的中断进行完之后,并不会直接退出,而是会进入中断回调函数中,用户可以在其中设置代码,串口中断接收完成之后,会进入该函数,该函数为空函数,用户需自行修改。

参数

⮚ UART_HandleTypeDef *huart UATR的别名
举例: HAL_UART_RxCpltCallback(&huart1) //用户设定的代码 //


串口中断处理函数:

HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  

功能:

对接收到的数据进行判断和处理,判断是发送中断还是接收中断,然后进行数据的发送和接收,在中断服务函数中使用。

如果接收数据,则会进行接收中断处理函数

 /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
   
    UART_Receive_IT(huart);
  

如果发送数据,则会进行发送中断处理函数

  /* UART in mode Transmitter ------------------------------------------------*/
  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  
    UART_Transmit_IT(huart);
    return;
  

2.3 串口查询函数

  HAL_UART_GetState();  判断UART的接收是否结束,或者发送数据是否忙碌

举例:

while(HAL_UART_GetState(&huart4) == HAL_UART_STATE_BUSY_TX) //检测UART发送结束

三、逻辑代码部分

3.1 UART接收中断

因为中断接收函数只能触发一次接收中断,所以我们需要在中断回调函数中再调用一次中断接收函数。

具体流程:

1、初始化串口

2、在main中第一次调用接收中断函数

3、进入接收中断,接收完数据 进入中断回调函数

4、修改HAL_UART_RxCpltCallback中断回调函数,处理接收的数据,

5、回调函数中要调用一次HAL_UART_Receive_IT函数,使得程序可以重新触发接收中断

函数流程:

①HAL_UART_Receive_IT (中断接收函数) ->
②USART2_IRQHandler(void) (中断服务函数) ->
③HAL_UART_IRQHandler(UART_HandleTypeDef *huart) (中断处理函数) ->
④UART_Receive_IT(UART_HandleTypeDef *huart) (接收函数) ->
⑤HAL_UART_RxCpltCallback(huart) (中断回调函数)

HAL_UART_RxCpltCallback函数就是用户要重写在main.c里的回调函数。

代码实现:

在main.c中添加下列定义:

#include <string.h>
 
#define RxBuffer_MaxSize  256     //最大接收字节数
char RxBuffer[RxBuffer_MaxSize];   //接收数据
uint8_t aRxBuffer;			//接收中断缓冲
uint8_t UART1_Rx_Cnt = 0;		//接收缓冲计数

在main()主函数中,调用一次接收中断函数

/* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
/* USER CODE END 2 */

在main.c下方添加中断回调函数

/* USER CODE BEGIN 4 */
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)


  UNUSED(huart);

 	if(UART1_Rx_Cnt >= 255)  //溢出判断
	
		UART1_Rx_Cnt = 0;
		memset(RxBuffer,0x00,sizeof(RxBuffer));
		HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", 10,0xFFFF); 	
  
	else
	
		RxBuffer[UART1_Rx_Cnt++] = aRxBuffer;   //接收数据转存
			if((RxBuffer[UART1_Rx_Cnt-1] == 0x0A)&&(RxBuffer[UART1_Rx_Cnt-2] == 0x0D)) //判断结束位
			//此处条件可以改写为if(RxBuffer[UART1_Rx_Cnt-1] == '\\n') 因为上面的条件就是表示回车
			
					HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, UART1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
          while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
				  HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_3);//LED指示灯状态翻转
					UART1_Rx_Cnt = 0;
					memset(RxBuffer,0x00,sizeof(RxBuffer)); //清空数组
			
	
		HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);   //再开启接收中断

/* USER CODE END 4 */

现象:

使用USB转TTL(CH340)进行数据发送,XCOM V2.6串口助手进行调试,发送“1”(这里要注意波特率等参数要设置的和之前配置的相同

在debug模式下,将缓冲计数值UART1_Rx_Cnt加入监视器,串口接收到发来的数据后,计数值+1.

同时也可以看到LED灯状态翻转

3.2 UART发送

重新定义printf函数

stm32f1xx_hal.c中包含#include <stdio.h>

#include "stm32f1xx_hal.h"
#include <stdio.h>
extern UART_HandleTypeDef huart1;   //声明串口

在 stm32f1xx_hal.c 中重写fget和fput函数

/**
  * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)

  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;

 
/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fgetc(FILE *f)

  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  return ch;

在main.c中添加

 #define RxBuffer_MaxSize  256
char RxBuffer[RxBuffer_MaxSize]; 
  while (1)
  
    /* USER CODE END WHILE */
			printf("hello world\\r\\n");//这里博主只写\\n的时候无法换行,百度了一下用\\r\\n就可以了,估计是编译系统的问题
			HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  

现象:


注意:
重定义printf后,必须在target里面勾选上MicroLIB,调用一下这个微型库,不然一直卡在里面。

参考博文:【STM32】HAL库 STM32CubeMX教程四—UART串口通信详解

以上是关于C语言变成实现串口收发数据的主要内容,如果未能解决你的问题,请参考以下文章

Raspberry Pi 3 ~ C语言控制串口

求一个C语言操作串口接受数据的程序,(传感器与电脑连接。需要读取传感器通过串口传歘的数据。)

想用C#写linux下的串口收发程序?

用C语言socket RAW功能实现同一台主机两个网口间数据收发

如何利用C语言,C++语言打开USB串口,然後对其发送信号? 跪求回答! 可行比加分!!

想在同一个串口中实现多线程收发通讯