51单片机笔记[8]-串口通信2

Proteus仿真时Virtual Terminal不显示弹出窗口

解决方法☞

调试->选中Virtual Terminal

STC-ISP生成代码

STC-ISP可以生成串口初始化代码

STC-ISP还可以下载到肯定能用的示例程序:

下载实验箱4程序包

虚拟串口的使用

[https://blog.csdn.net/farsight_2098/article/details/90210349]
[https://www.cnblogs.com/zhenghaoyu/p/10059848.html]
软件:VSPD(虚拟串口)和串口调试助手


虚拟串口软件激活COM1和COM2,
COM1负责发送数据,COM2负责接收数据


因而,串口调试助手连接COM2,Proteus相应元件绑定COM1.COM2模拟另一台设备向COM1发送/接收数据
,波特率两边一致即可

串口实现命令

已知的bug:仿真时一会儿就会卡死,好像接收数据有问题

/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/*------------------------------------------------------*/
#include <stc15f2k60s2.h>
#include "intrins.h"
#include <stdio.h>
typedef unsigned char BYTE;
typedef unsigned int WORD;

#define FOSC 12000000L          //系统频率
#define BAUD 9600             //串口波特率

#define NONE_PARITY     0       //无校验
#define ODD_PARITY      1       //奇校验
#define EVEN_PARITY     2       //偶校验
#define MARK_PARITY     3       //标记校验
#define SPACE_PARITY    4       //空白校验

#define PARITYBIT NONE_PARITY   //定义校验位
#ifndef __STC15_H__
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xC9;
sfr P5M0 = 0xCA;
sfr P6M1 = 0xCB;
sfr P6M0 = 0xCC;
sfr P7M1 = 0xE1;
sfr P7M0 = 0xE2;

sfr AUXR  = 0x8e;               //辅助寄存器

sfr P_SW1   = 0xA2;             //外设功能切换寄存器1



sbit P22 = P2^2;
#endif
#define S1_S0 0x40              //P_SW1.6
#define S1_S1 0x80              //P_SW1.7
bit busy;
/*
********************全局变量***************************
*/
#define uchar unsigned char
#define uint unsigned int
#define time 100	//在接收函数中通过判断是否接收超时来判断字符串是否接收完毕

#ifndef S4RI
#define S4RI  0x01              //S4CON.0
#define S4TI  0x02              //S4CON.1
#endif
#define send_string SendString
unsigned char code distab[16] = {
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};//0-F
//字符串开始$,字符串结束#
int _dollar=0;
int _diese=0;
//接收/发送数据变量
uchar rec_data;
uchar send_data;
unsigned char *rec_data_array;
char send_data_array[25];
char code xuehao[]="$xuaohao:20211009128#\n";
/*
 指令含义(ASCII):
$+数字+#  数码管显示数字
$+字母+#  流水灯字母状态
 */
#define SMG P7
sbit KEY = P3^3;
sbit LED1=P4^6;
sbit LED2=P4^7;
//按键状态
int count=-1;
/*
*********************结束全局变量************************
*/
//函数声明
void SendData(BYTE dat);
void SendString(char *s);
void delay(int);
void smg_display(int);
void led(uchar);
void ana_command(unsigned char*);
void key_scan();
unsigned char* Receive(int rec_i);
void main()
{
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;
    P6M0 = 0x00;
    P6M1 = 0x00;
    P7M0 = 0x00;
    P7M1 = 0x00;

    ACC = P_SW1;
    ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=0
    P_SW1 = ACC;                //(P3.0/RxD, P3.1/TxD)
    
//  ACC = P_SW1;
//  ACC &= ~(S1_S0 | S1_S1);    //S1_S0=1 S1_S1=0
//  ACC |= S1_S0;               //(P3.6/RxD_2, P3.7/TxD_2)
//  P_SW1 = ACC;
//
//  ACC = P_SW1;
//  ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=1
//  ACC |= S1_S1;               //(P1.6/RxD_3, P1.7/TxD_3)
//  P_SW1 = ACC;

#if (PARITYBIT == NONE_PARITY)
    SCON = 0x50;                //8位可变波特率
#elif (PARITYBIT == ODD_PARITY) || (PARITYBIT == EVEN_PARITY) || (PARITYBIT == MARK_PARITY)
    SCON = 0xda;                //9位可变波特率,校验位初始为1
#elif (PARITYBIT == SPACE_PARITY)
    SCON = 0xd2;                //9位可变波特率,校验位初始为0
#endif

    AUXR = 0x40;                //定时器1为1T模式
    TMOD = 0x00;                //定时器1为模式0(16位自动重载)
    TL1 = (65536 - (FOSC/4/BAUD));   //设置波特率重装值
    TH1 = (65536 - (FOSC/4/BAUD))>>8;
    TR1 = 1;                    //定时器1开始启动
    ES = 1;                     //使能串口中断
    EA = 1;

/**
 用户程序
 */
 						smg_display(4);
						led('B');
            SendString(xuehao);
						delay(1000);
    while(1){

            key_scan();
						rec_data_array=Receive(3);
						if(*rec_data_array){
							send_string(rec_data_array);
							//LED2=~LED2;
						}
						ana_command(rec_data_array);
        }
}

/*----------------------------
UART 中断服务程序
-----------------------------*/
void Uart() interrupt 4
{
    if (RI)
    {
        RI = 0;                 //清除RI位
        P0 = SBUF;              //P0显示串口数据
        P22 = RB8;              //P2.2显示校验位
    }
    if (TI)
    {
        TI = 0;                 //清除TI位
        busy = 0;               //清忙标志
    }
}

/*----------------------------
发送串口数据
----------------------------*/
void SendData(BYTE dat)
{
    while (busy);               //等待前面的数据发送完成
    ACC = dat;                  //获取校验位P (PSW.0)
    if (P)                      //根据P来设置校验位
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 0;                //设置校验位为0
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 1;                //设置校验位为1
#endif
    }
    else
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 1;                //设置校验位为1
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 0;                //设置校验位为0
#endif
    }
    busy = 1;
    SBUF = ACC;                 //写数据到UART数据寄存器
}

/*----------------------------
发送字符串
----------------------------*/
void SendString(char *s)
{
    while (*s)                  //检测字符串结束标志
    {
        SendData(*s++);         //发送当前字符
    }
}

void delay(int ms){//@12MHz
    int i,j;
    for(i=0;i<ms;i++){
        for(j=0;j<1000;j++);
    }
}
//数码管
void smg_display(int num){
    SMG = ~distab[num];
}
//LED灯
void led(uchar status){
    switch(status){
        case 'A':LED1=0;LED2=0;break;
        case 'B':LED1=1;LED2=0;break;
        case 'C':LED1=0;LED2=1;break;
        case 'D':LED1=1;LED2=1;break;
        default:LED1=1;LED2=0;
    }
}
//解析指令
void ana_command(uchar *dat){
    if(*dat=="$0#"){
        //数码管0
        smg_display(0);
				send_string("received:0");
    }
    if(*dat=="$1#"){
        //数码管1
        smg_display(1);
			send_string("received:1");
    }
    if(*dat=="$2#"){
        //数码管2
        smg_display(2);
    }
    if(*dat=="$3#"){
        //数码管3
        smg_display(3);
    }
    if(*dat=="$4#"){
        //数码管4
        smg_display(4);
    }
    if(*dat=="$5#"){
        //数码管5
        smg_display(5);
    }
    if(*dat=="$6#"){
        //数码管6
        smg_display(6);
    }
    if(*dat=="$7#"){
        //数码管7
        smg_display(7);
    }
    if(*dat=="$8#"){
        //数码管8
        smg_display(8);
    }
    if(*dat=="$9#"){
        //数码管9
        smg_display(9);
    }
    if(*dat=="$A#"){
        led('A');
			send_string("received:A");
    }
    if(*dat=="$B#"){
        led('B');
			send_string("received:B");
    }
    if(*dat=="$C#"){
        led('C');
			send_string("received:C");
    }
    if(*dat=="$D#"){
        led('D');
			send_string("received:D");
    }
}
//按键监听
void key_scan(){
    uchar temp[5];
    if(KEY==0){
        delay(200);
        if(KEY==0){
            count++;
            if(count>9) count=0;
            smg_display(count);
            LED1=~LED1;LED2=~LED2;
            sprintf(temp,"$%d#",count);
            send_string(temp);
						//sprintf(temp,"$%c#",'A');
            //send_string(temp);
        }
    }
}
//字符串接受
unsigned char* Receive(int rec_i)
{
	int rec_fin_flag=0;
	//unsigned count=0;		//超时机制 用于短暂计数用作延时
	unsigned char rec_str[6];
	//unsigned char* rec_str;
	unsigned count1;
	while(rec_fin_flag!=1)  
	{
		rec_str[rec_i]=SBUF;
		RI=0;
		rec_i++;
		count1=0;
		while(rec_fin_flag==0)
		{
			if(RI==1)	break;
			count1++;
			if(count1==time) rec_fin_flag=1;
		}
	} 	
	RI=0;
	return rec_str; 	
}

效果

#include "reg52.h"
#include <stdio.h>
//uint 和 uchar近似等同
#define uchar unsigned char
#define uint unsigned int

/**全局变量*/
int count=0;
int num=0;
char *xuehao="xuehao:20211009128\n";
char *received_string;
unsigned char code table[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
    0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
    };//smg-共阴
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit LED1=P2^0;
sbit LED2=P2^1;
bit busy=0;
#define SMG  P0;
#define LED  P2;
uchar com_temp;//串口数据传递
/**结束全局变量*/


/**函数头部声明*/
void delay(int ms);
void init_uart();
void key_scan();
void show_num(int num);
void led(int status);
void send_string(char*);
void rec_string(char *);//接收字符串
void ana_string(char *);//分析字符串
/**结束函数头部声明*/


//主函数
void main(){
    init_uart();
        send_string("welcome to 51 mcu sys!\n");
    send_string("author:20211009128\n");
        send_string("please send command!\n");
        //P0=table[5];
        show_num(2);
        led(1);
    while(1){
        key_scan();
        rec_string(received_string);
        if(*received_string) ana_string(received_string);
    }
}
/**函数本体*/
void delay(int ms){
    int i,j;
    for(i=0;i<ms;i++){
        for(j=0;j<1000;j++);
    }
}
//中断方式
//如果是查询方式,ES=0;EA=0;
void init_uart(){//9600bps@12MHz
    TMOD|=0X20;    //设置计数器工作方式2
    SCON=0X50;    //设置为工作方式1
    PCON=0X80;    //波特率加倍
    TH1=0xFA;    //计数器初始值设置
    TL1=0xFA;
    ES=1;        //打开接收中断
    EA=1;        //打开总中断
    TR1=1;        //打开计数器
    delay(100);//100ms
}
//中断函数
void uart() interrupt 4 {//串口通信中断函数
    uchar rec_data;
if(RI){
    RI = 0;            //清除接收中断标志位
    rec_data=SBUF;    //存储接收到的数据
}
if(com_temp){//如果非空
    SBUF=com_temp;    //数据放入到发送寄存器
    if(TI){
    TI=0;            //清除发送完成标志位
    busy=0;//空闲
    }
rec_data=com_temp;//传递到全局变量
    delay(5000);
}
}
//按键扫描
void key_scan(){
    if(KEY1==0){
        delay(1);
            if(KEY1==0){
                int k;
               send_string("xuehao:20211009128\n");
            }
        }
    if(KEY2==0){
        delay(1);
            if(KEY2==0){
                show_num(count);
                num++;
                if(num>9) num=0;
                }
            }
        }

//数码管显示
void show_num(int num){
    if(num<=9 || num>=0){
    P0=table[num];
    }
}
//发送字符串
void send_string(char *input){
    while(*input){//检查是否到结尾
        while(busy);//等待上一帧数据发送完毕
        busy=1;
        SBUF=*input++;
                delay(1);
              busy=0;
    }
}
//接收字符串
void rec_string(char *input){
    while(busy);//等待串口
    busy=1;
   // static int _count=0;
    while(count<20 || com_temp!='#'){
        count++;
                if(count>20) count=0;
        *input=com_temp;
                *input++;
    }
        send_string(input);
        busy=0;
    *input='#';
}
//流水灯
void led(int status){
    int k;
    switch (status) {
        case 1:
            for(k=0;k<8;k++){
                P2=(1<<k);
                delay(10);
            }
            break;
            
        default:
            P2=0x02;
            delay(1);
            P2=0x08;
            delay(1);
            break;
    }
}
//分析字符串
void ana_string(char *input){
    if(*input=='#') show_num(0);
    if(*input=='1') led(1);
    else{
        led(2);//default
    }
}
/**bugfixed
 1.PC端只能接收到一个数据、而非连续的数据
 while(!TI);      //当发送到停止位时  TI自动变为1;    while(!TI)和while(TI == 1)是不一样的
 2.pc端接受数据时,第一个数据总为00.
 初始化串口不能立马发送数据,需要一个短暂的延迟!
delay(100);//100ms
 */

效果:

posted @ 2022-09-25 18:01  qsBye  阅读(416)  评论(0编辑  收藏  举报