文章目录
- 一、芯片简介
- 二、开发环境
- 三、软件模拟串口
- 参考
一、芯片简介
STC15F100系列单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机,新一代8051单片机,指令代码完全兼容传统8051,但是速度快6-12倍。
内部集成R/C时钟,5MHz~35MHz宽范围可设置,可以省掉外部晶振。
内部集成复位电路,可省掉外部复位电路。
6个通用I/O口,支持四种模式:准双向口/弱上拉、强推挽/强上拉、输入/高阻、开漏
芯片管脚图
二、开发环境
在Keil中添加STC芯片
-
下载STC-ISP软件
https://www.stcmcudata.com/ -
打开STC-ISP软件,选择右侧"Keil仿真设置"栏
-
选择"添加型号和头文件到Keil中,添加STC仿真器驱动到Keil中", 选择Keil C51的安装目录
例如:D:/software/keil4 -
系统会自动添加"STC"文件夹( C51/INC/ )
-
Keil新建工程选择芯片型号时就会有新添加的STC芯片
三、软件模拟串口
STC15F100E芯片内部是不直接支持串口通信的,但是可以用I/O口+定时器来实现串口功能。
这里实现的是半双工通信
。
系统工作时钟为5.5296Mhz,波特率为9600bps。
引脚说明
- P3.0为Uart的RX引脚
- P3.1为Uart的TX引脚
原理说明
- 发送原理
设置定时器的定时时间为一个bit的的发送时间,在定时器中断服务函数中,设置Uart_TX引脚的值。 - 接收原理
将Uart_RX引脚设置为外部中断(下降沿触发)模式,捕获Uart接收的开始信号。
设置第一次定时时间为 3 2 \frac{3}{2} 23个bit持续的时间,其余的定时时间为一个bit的持续时间,在定时器中断服务函数中对Uart_RX引脚进行采样。
程序
- uart.c
/*
module name : uart
author : wkk
create time : 2023/12/5
*/
#include "uart.h"
/*
BaudRate -> timer
SysClk : 5.5296Mhz
Baudrate : 115200
5_529_600 / 115200 = 48 ( x -> error )
5_529_600 / 9600 = 576
65536 - 48 = 65488 0xffd0
65536 - 48-24 = 65464 0xffb8
65536 - 576 = 64960 0xfdc0
65536 - 576-288 = 64672 0xfca0
*/
// define type u8
typedef unsigned char u8;
// ext 2 3 4 register
// 7 6 5 4 3 2 1 0
// - ext4 ext3 ext2 - - tlclkO t0clkO
sfr int_clkO = 0x8f;
// 1T mode or /12
// 7 6 5 4 3 2 1 0
// t0x12 t1x12 - T2R T2_C/T T2x12 - -
sfr auxr = 0x8e;
// IE2
// 7 6 5 4 3 2 1 9
// - ET4 ET3 ES4 ES3 ET2 ESP1 ES2
sfr ie2 = 0xaf;
// timer
sfr TH2 = 0xd6;
sfr TL2 = 0xd7;
//define uart tx/rx port
sbit uart_rx = P3^0; // P3.0 rx
sbit uart_tx = P3^1; // P3.1 tx
u8 TEND,TING,tcnt,tbuf;
u8 REND,RING,rcnt,rbuf;
void Enable_Ext4(){
int_clkO = int_clkO | 0x40;
}
void Disable_Ext4(){
int_clkO = int_clkO & 0xbf;
}
void Timer2_config(){
// 1T mode
auxr = auxr & 0xf0;
auxr = auxr | 0x04;
// enable timer1 interrupt
ie2 = ie2 | 0x04;
// need to enable EA
}
void Timer2_Disable(){
auxr = auxr & 0xef;
}
void Timer2_Enable(u8 th1,u8 tl1){
TH2 = th1;
TL2 = tl1;
auxr = auxr | 0x10;
}
void Uart_Init(){
//P3.0 work in interrupt mode ( int4 falling )
Enable_Ext4();
// timer2 config
Timer2_config();
Timer2_Disable();
// need to enable EA
TEND = 1;
REND = 0;
TING = 0;
RING = 0;
uart_tx = 1;
}
void Ext4_Interrupt() interrupt 16 {
RING = 1;
REND = 0;
rcnt = 0;
rbuf = 0;
Timer2_Enable(0xfc,0xa0);
Disable_Ext4();
}
void Uart_SendByte( u8 tx_data ) {
tbuf = tx_data;
tcnt = 0;
TEND = 0;
TING = 1;
uart_tx = 0;
Timer2_Enable(0xfd,0xc0);
while( TEND != 1); // wait for tx complete!!
}
void Uart_LoopTest( ){
if( TEND && REND == 1 ) {
Uart_SendByte(rbuf);
REND = 0;
}
}
void Timer2_Interrupt() interrupt 12 {
if( RING ) {
if( rcnt == 0 ) {
Timer2_Disable();
rbuf = rbuf >> 1;
if( uart_rx ) rbuf = rbuf | 0x80;
Timer2_Enable(0xfd,0xc0);
}else if( rcnt == 8 ){
Timer2_Disable();
Enable_Ext4();
RING = 0;
REND = 1;
// recv done !!!
}else {
rbuf = rbuf >> 1;
if( uart_rx ) rbuf = rbuf | 0x80;
}
rcnt ++;
}else if( TING ) {
if( tcnt == 8) {
uart_tx = 1;
}else if( tcnt == 9) {
Timer2_Disable();
TING = 0;
TEND = 1;
// tx done !!!
}else{
uart_tx = tbuf & 0x01;
tbuf = tbuf >> 1;
}
tcnt ++;
}else{
// other things
}
}
- uart.h
#ifndef _UART_H_
#define _UART_H_
#include <reg51.h>
void Uart_Init(void);
void Uart_SendByte( unsigned char tx_data );
void Uart_LoopTest( void );
#endif
- main.c
#include <reg51.h>
#include "uart.h"
void Sys_Init(){
Uart_Init();
EA = 1;
}
void main(){
Sys_Init();
while(1) {
//Uart_LoopTest();
}
}
参考
- 定时器相关
https://blog.csdn.net/weixin_52853526/article/details/125180813 - 模拟串口程序
https://www.cnblogs.com/zjutlitao/archive/2018/03/31/8681049.html - 右移/左移和标志位CY的关系