目录
- 1.串口与PC通信的接线
- 芯片与芯片之间的通讯:
- 芯片与电脑之间的通讯:
- 2.利用实验箱示例代码移植驱动程序
- 3.串口通信实战
- 最小工程
- 代码移植
- 编译提示错误:undefined identifier
1.串口与PC通信的接线
上节试验是串口和电脑进行一个通信,用了一根USB转232的线,直接插到了我们这个板子上。今天详细解释一下是怎么样接线。
每一个TD和一个RXD代表一组端口,就是一组串口。
看DIP40的管脚功能图:
TXD_几和RXD_几表示这是该组串口的第几个通道,1是默认省略的。通道是分时打开,也叫分时复用。
MCU串口出来的信号都是TTL电平。
TTL电平信号规定,+5V等价于逻辑“1”,0V等价于逻辑“0”(采用二进制来表示数据时)。这样的数据通信及电平规定方式,被称做TTL(晶体管-晶体管逻辑电平)信号系统。
芯片与芯片之间的通讯:
如果通信协议和电平都一样,直接TX和RX链接就可以通信。
芯片与电脑之间的通讯:
电脑没有TXD跟RXD的这个接口(以前的电脑有232接口)
串口能直接和电脑USB通信吗?不能直接通信,因为电脑没有串口。需借助USB转TTL的工具。
它中间用了颗芯片,去做电平的转化或者协议的转化,芯片常见的有CH340、CP2102,电脑还需要另外的去装驱动。
推荐使用如上的官方工具。
程序无需任何处理,抗干扰能力更强!
一个USB工具可以转2个串口,代替2个。
四个端子分别是接到了P47、P50、P46、P51。
再看看USB转TTL的模块,学名是:一箭双雕之USB转双串口。需要根据官方介绍,刷成USB转双串口的功能。占用1个usb口,2路串口输出。
S-RXD是STC-CDC1串口的发送脚,连接其它串口的接收脚。S-TXD是STC-CDC1串口的接收脚。连接其它串口的发送脚。
S-RXD本质上是TX,S-TXD本质上是RX,这么标注是为了方便用户接线。
一般使用同一组串口。一箭双雕还有OLED接口,4个led的流水灯等等。
USB转232通讯线。板载232端口(DB9母头)和电平转换电路。考虑到传输距离和抗干扰性的问题,中间就可以考虑使用TTL转232,相互去转化。
TTL转232程序上无需任何处理,但抗干扰能力增强。实际项目中,如果距离有一定要求,可以采用此方式。甚至485,422。只要逻辑电平能对得上,就可以互相连接。
2.利用实验箱示例代码移植驱动程序
1)查找试验箱里面和我们的功能最接近的程序。如:11-串口2中断模式与电脑收发测试
上节课也用串口2,是根据手册编写的代码,后期一定要灵活运用程序包。官方提供的程序包里面官方都已经测试好了,不用去熟悉每一个寄存器,只要按照代码包里的寄存器配好就可以使用了。
代码包里每一个试验都已经做到了最简单,不用从几万行代码里去扣出几十行几百行你有用的代码,每一个小实验对应一个功能。本节讲串口2,可以直接移植例程。
2)先测试示例程序是否正常运行。
一定先试验测试,再移植。
3)分析哪些代码与我们的功能有用。
只移植对我们有用的东西。
4)新建文件,开始移植。
尽量避免大部分无用的手敲,只需要学会怎么去移植就可以。
3.串口通信实战
打开待参考的11-串口2中断模式与电脑收发测试代码包(C语言),再将上一节的16.串口2通信复制并更名为17.串口PC通信,打开工程,在其基础上进行移植。
同时打开以上2个工程,屏幕右边方示例代码,左边打开我们要需要的工程。
先从主函数开始看,提升指令速度等原工程里都有(见sys_init()),明显不需要设为准双向口。
选择波特率这行初始化没有,应该有用,选中这行并复制到新工程内,示例模板里是放在端口初始化之后,我们也放在sys_init()初始化之后。
最小工程
把工程里不必要的东西清理一下,保留最小工程,如:
#include "COMM/stc.h" //调用头文件
#include "COMM/usb.h"
#include "seg_led.h"
#include "key.h"
#include "beep.h"
#include "tim0.h"
#include "exit.h"
#include "adc.h"
#include "ntc.h"
#include "usart2.h"char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";bit TIM_10MS_Flag; //10ms的标志位
u16 Tme_CountDown = 0; //全局变量void sys_init(); //函数声明
void delay_ms(u16 ms); //unsigned intvoid main() //程序开始运行的入口
{sys_init(); //USB功能+IO口初始化UART2_config(2); // 选择波特率, 2: 使用Timer2做波特率, 1其它值: 无效.1usb_init(); //usb库初始化Timer0_Init(); //定时器0初始化EA = 1; //CPU开放中断,打开总中断。while(1) //死循环{if( TIM_10MS_Flag==1 ) //如果10ms到了{TIM_10MS_Flag = 0; //清空标志位}}
}void Timer0_Isr(void) interrupt 1
{static timcount = 0;SEG_LED_Show(); //数码管刷新的timcount++; //1ms+1if( timcount>=10 ) //如果这个变量大于等于10,10ms计数到达{timcount = 0;TIM_10MS_Flag = 1; //10ms时间到了}
}void sys_init() //函数定义
{WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快EAXFR = 1; //扩展寄存器(XFR)访问使能CKCON = 0; //提高访问XRAM速度P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口P3M0 = 0x00;P3M1 = 0x00;P3M0 &= ~0x03;P3M1 |= 0x03;//设置USB使用的时钟源IRC48MCR = 0x80; //使能内部48M高速IRCwhile (!(IRC48MCR & 0x01)); //等待时钟稳定USBCLK = 0x00; //使用CDC功能需要使用这两行,HID功能禁用这两行。USBCON = 0x90;
}void delay_ms(u16 ms) //unsigned int
{u16 i;do{i = MAIN_Fosc/6000;while(--i);}while(--ms);
}
先对示例代码进行测试,复制E:\STC32\STC32G-DEMO-CODE-V9.6-20230425\COMM文件夹至待移植工程目录,并添加include文件路径,将成功编译后的文件载入开发板。下载时选择主频为22.1184。
看一下示例程序里使用的引脚,在UART2_config(2)上跳转初始化,S2_S = 1; //UART2 switch to: 0: P1.0 P1.1, 1: P4.6 P4.7,选择的是P4.6和P4.7。
正常运行时,板子无任何变化,选择USB转232所在的串口,再看一下程序里的波特率为115200(#define Baudrate2 (65536 - MAIN_Fosc / 115200 / 4)),常用的还有9600。无校验,停止位1。打开串口,发送数据后返回一模一样的数据。执行的主要代码段为:
while (1){if((TX2_Cnt != RX2_Cnt) && (!B_TX2_Busy)) //收到数据, 发送空闲{S2BUF = RX2_Buffer[TX2_Cnt];B_TX2_Busy = 1;if(++TX2_Cnt >= UART2_BUF_LENGTH) TX2_Cnt = 0;}}
示例代码验证完,没有问题,可以移植。
代码移植
首先打开刚才的最小工程,然后选择波特率的这行复制好了,EA=1总中断开启。把PrintString2()函数也复制过来。初始化完成后,打印一个字符串。代码中的小红点是仿真时的断点,也可以做为每次编写代码的位置提示。
再把while主循环部分的执行代码复制移植过来,放在10ms执行标识前,可以把USB下载的代码段取消注释,方便下载。
转到UART2_config(2)的定义,看看详细定义方法。移植该功能代码前,将上节课的串口模块.C和.H文件中自编代码部分删除。
首先函数需要先移植过来,添加声明,复制UART2_config函数定义,再讲其下的中断函数复制过来(除中断函数外,其他函数都需要声明才可以使用)。中断函数和上节代码一样,不详细讲解了。UART2_config里还有设置串口函数SetTimer2Baudraye,移植过来(声明并复制定义)。
接下来在看看函数中的变量,以PrintString2为例,右击变量名称B_TX2_Busy,转向到定义文件,找到定义。
如果想主函数中也能使用这些变量,需要在usart.h中重新定义,在变量名前加extern:
extern u8 TX2_Cnt; //发送计数
extern u8 RX2_Cnt; //接收计数
extern bit B_TX2_Busy; //发送忙标志extern u8 RX2_Buffer[UART2_BUF_LENGTH]; //接收缓冲
这样在别的任意的.C文件中,引用头文件usart.h就可以调用这些变量。调用前需要在相应的.C文件前部增加变量声明(不赋初始值),如在usart.c中增加:
#include "usart2.h"u8 TX2_Cnt; //发送计数
u8 RX2_Cnt; //接收计数
bit B_TX2_Busy; //发送忙标志u8 RX2_Buffer[UART2_BUF_LENGTH]; //接收缓冲
修改主时钟:#define MAIN_Fosc 22118400L //定义主时钟(精确计算115200波特率)。复制宏定义Baudrate2和UART2_BUF_LENGTH。至此,完成移植。
编译提示错误:undefined identifier
编译,提示错误:HARDWARE\USART\usart2.c(67): error C67: ‘T2_CT’: undefined identifier,没有定义。
在示例模板中找一下T2_CT,右击转向定义,在stc32g.h头文件中,sbit T2_CT = AUXR^3;AUXR寄存器的第3位。手册中搜索AUXR:
地址在0X8E,按这个地址去找,如下:
不建议直接修改头文件(以前的代码都用同样的头文件),可以修改程序中的定义为T2CT,修改完后重新编译,下载进去(实验箱的代码里大部分都没有CDC串口,需要手动进入下载模式)。串口工具中发送文字,能够接收到回显文字,移植成功。
以后的工程中如果用到3个串口,不要再跟着手册去敲,只需要把示例代码,下载到板子里去测试,没问题就可以移植过来了。实验箱中的代码基本上main.c就搞定了,实际做工程的时候,有串口2,NTC,有ADC外部中断,有定时器0等等,不可能全都放在demo.c里面。