STC15F104W的串口是哪些引脚?
P3.0和P3.1可以做串口吗?我记得只能用于下载,不能用于用户串口通讯。
不过准确的话,还得看一下手册 。
没有涉及到串口的内容
xxkj2010 发表于 2024-1-17 09:46
没有涉及到串口的内容
谢谢,就是因为看手册上没有,才来问问看 选型表里面可以看到,STC15F1xx系列芯片没有串口功能
这型号还没有定时器1呢,这点也得注意,我有一次就因此掉坑的。
15不是停产了吗 2012年用STC15F104E做了一些485继电器控制小板,自己自制智能家居。
后面出了104W,就换了104W
后面又出了104WS,就自带串口了。
当时硬是用模拟串口做出来了,可以跑115200bps。
#include <reg52.h> //使用8052内核单片机
#include <intrins.h> //使用_nop_();
sbit IO1=P3^5; //IO
sbit IO2=P3^4; //IO
sbit IO3=P3^3; //IO
sbit DE_RE=P3^2; //智能家居485总线流控方向,1发送,0接收
sbit TX_IO=P3^1; //模拟串口发送IO
sbit RX_IO=P3^0; //模拟串口接收IO
sfr AUXR=0x8e; //STC15F104E系列单片机特殊寄存器,控制定时器时钟来源频率
sfr P3M0=0xb2; //P3IO口工作模式
sfr eeprom_data =0xc2;
sfr eeprom_addh =0xc3;
sfr eeprom_addl =0xc4;
sfr eeprom_cmd=0xc5;
sfr eeprom_star =0xc6;
sfr eeprom_cont =0xc7;
bit sending,receing,stpbsed,bytereceived; //发送中,接收中,接收完毕标志
bit data_receive_enable; //帧头判断成功,过零信号前一状态
bit trig_count_enable1; //过零信号到达启动计时
bit trig_count_enable2; //过零信号到达启动计时
bit traic_1_on,traic_2_on;
unsigned char rece_bit_count; //接收位计数变量
unsigned char rece_pls_count; //接收脉冲计数变量
unsigned char send_bit_count; //发送位计数变量
unsigned char send_pls_count; //发送脉冲计数变量
unsigned char receing_data; //正在接收着的临时数据
unsigned char byte_need_to_send; //要发送出去的字节
unsigned char byte_received; //已收到的字节
unsigned char zhen_tou[]={0xFF,0x00,0x55,0xAA,0x00,0xFF};//帧头字串
unsigned char cast_tou[]={0xFF,0x00,0x55,0xAA,0xFF,0x00};//广播地址帧头
unsigned char jie_shou[]={0x00,0x00,0x00,0x00,0x00,0x00};//接收的数据帧
unsigned int code baud[]={0xa000,0xd000,0xe800,0xf400,0xfa00,0xfd00,0xfe00,0xff00,0xff25,0xff80,0xffc0};
//300-----600----1200---2400---4800---9600---14400--28800--33600--57600--115200
//smod=1@22.1184mhz,auxr|=0x80
unsigned char count,checksum,temp; //处理数据帧字节计数,校验和,临时传递变量
unsigned char etmp1,etmp2; //操作eeprom用的临时保存变量
unsigned char verify,fr_num; //帧头核对及数据帧接收位置
unsigned char com_bit_tick; //串口位节拍计时器,主要用作回包延时控制
unsigned char trig_count1; //移相触发延时变量
unsigned char trig_count2; //移相触发延时变量
unsigned char brightness1,brightness2; //可控硅亮度
unsigned intbootdelay,baud_index; //启动延时,波特率索引值
//eeprom 命令:0空闲,1读字节,2写字节,3扇区擦除
//写到eeprom_cont 寄存器的值:0x81,小于24MHz
//eepROM 起始地址:0x0000,0x0000-0x01ff 第一扇区 0x0200-0x03ff第二扇区
void close_eeprom(void);
unsigned char read_eeprom(unsigned int addr);
void write_eeprom(unsigned int addr,dat);
void erase_eeprom(unsigned int addr);
void send_byte(unsigned char byte_will_send); //发送一个字节
unsigned char pack_ana(void);
void set_baud(unsigned char index);
void respond_packge(void);
void execute_cmd(void);
void byte_reced(void);
void traic_on_off(void);
void main(void) //主程序
{ //开始
unsigned long btn_push_count;
P3=0XCF;
AUXR=0xc0; //T0计时脉冲不分频,比传统8051快12倍
P3M0=0X3c;//00111100
TMOD=0X00; //16位自动重载模式,当TR0=0时向TH0,TL0写入数据将同时写入重载寄存器
TH0=0xfd; //重载值=65536-(定时器脉冲频率÷波特率÷3)
TL0=0x00; //溢出率=定时器脉冲频率÷(65536-重载值)
TH1=0xFB;
TL1=0xAE; //50uS@22.1184mhz计数率
TR0=1; //启动定时器,模拟串口开始工作
TR1=1; //启动定时器,可控硅移相触发开始工作
EA=1; //打开总中断
ET0=1; //打开定时器0中断
ET1=1; //打开定时器1中断
PT0=1; //优先保证定时器0中断,确保模拟串口的可靠性
DE_RE=0;
bootdelay=15000;
etmp1=35;
while(--etmp1)
{
while(--bootdelay)
{
byte_reced();
}
}
baud_index=read_eeprom(0x0001);
set_baud(baud_index);
zhen_tou=read_eeprom(0x0000);
zhen_tou=~zhen_tou;
brightness1=read_eeprom(0x0200);
brightness2=read_eeprom(0x0201);
traic_on_off();
while(1) //主循环
{ //主循环体开始
byte_reced();
if(TX_IO==0)
{
while(TX_IO==0)
{
btn_push_count++;
}
if(btn_push_count>200000 && btn_push_count<500000){IO1=~IO1;}
if(btn_push_count>500000 && btn_push_count<1500000){IO2=~IO2;}
if(btn_push_count>1800000){IO3=~IO3;}
btn_push_count=0;
}
//send_byte(0X55);
} //主循环体结束
} //主程序结束
void send_byte(unsigned char byte_will_send) //发送一个字节
{ //函数开始
byte_need_to_send=byte_will_send; //传递要发送的数据
send_pls_count=3; //采样倍率3
send_bit_count=8; //8位数据一位停止
TX_IO=0; //发送起始位
sending=1; //置标志位,中断程序开始发送该字节
stpbsed=0;
while(sending==1); //等待数据发送完成
} //函数结束
void timer0(void) interrupt 1 //中断服务程序
{ //函数开始
// IO3=!IO3;
if(receing) //接收中?
{ //接收中开始
if(--rece_pls_count==0) //三次脉冲计数够了吗?
{ //接收一位二进制位开始
rece_pls_count=3; //脉冲计数辅助变量复位
if(rece_bit_count) //是在接收数据位还是停止位
{ //接收数据位开始
receing_data=receing_data>>1; //向右移一位,准备拼入一位二进制数据
if(RX_IO==1){receing_data=receing_data|0x80;}//如果收到的是二进制位"1",则拼入最高位中
rece_bit_count=rece_bit_count-1; //已接收一位,接收位计数变量计数
} //接收数据位结束
else //如果已经收完8位数据
{ //就开始接收停止位
receing=0; //本字节已接收完毕
if(RX_IO==1) //停止位是"1"吗
{ //是“1”
byte_received=receing_data; //将数据输出
bytereceived=1;
//------------------------------------------------//知道了……
} //数据输出处理完毕
} //停止位处理完毕
} //接收一位二进制位结束
} //接收中处理结束
else //还没收到停止位,不是正在接收状态
{ //等待接收开始
if(RX_IO==0) //是一个起始位到来吗
{ //是.......
receing=1; //开始接收
rece_pls_count=4; //置接收起始位脉冲数
rece_bit_count=8; //置接收二进制位数
} //起始位处理完毕
} //等待接收完毕
//----------------------------------------------------------------------------------------
if(sending) //是正在发送状态吗
{ //是……
if(--send_pls_count==0) //脉冲计数够了吗
{ //够了……
send_pls_count=3; //脉冲计数复位
if(send_bit_count) //是在发送数据还是要发送停止位
{ //发送数据开始
TX_IO=byte_need_to_send&0x01; //从最低位开始发送数据
byte_need_to_send=byte_need_to_send>>1; //移动数据准备下一次发送
send_bit_count=send_bit_count-1; //已经发送了一位二进制数要记下来
} //发送数据结束
else //数据已经发送完成
{ //发送停止位开始
if(stpbsed)
{
sending=0; //放下旗帜表示数据已经发送完成
}
TX_IO=1; //发送停止位
stpbsed=1;
} //停止位发送完成
} //一位二进制位处理完成
} //发送状态处理完成
com_bit_tick--; //串口位时间滴答向下
} //中断函数结束
void timer1(void) interrupt 3 //中断服务程序
{
if(IO3==0) //一个新的过零信号到来了吗
{
trig_count_enable1=1;
trig_count_enable2=1;
}
if(traic_1_on==1)
{
IO2=0;
if(trig_count_enable1==1)
{
trig_count1++;
if(trig_count1>=brightness1)
{
trig_count_enable1=0;
trig_count1=0;
IO2=1;
}
}
}
if(traic_2_on==1)
{
IO1=0;
if(trig_count_enable2==1)
{
trig_count2++;
if(trig_count2>=brightness2)
{
trig_count_enable2=0;
trig_count2=0;
IO1=1;
}
}
}
}
unsigned char pack_ana(void)
{
checksum=0;
for(count=0;count<6;count++)
{
checksum=checksum+zhen_tou;
}
for(count=0;count<5;count++)
{
checksum=checksum+jie_shou;
}
if(checksum==jie_shou)
{
return(1);
}
else
{
return(0);
}
}
void set_baud(unsigned char index)
{
if(index>10) //faild value
{
index=5;
}
TR0=0; //启动定时器,模拟串口开始工作
TH0=baud/256; //重载值=65536-(定时器脉冲频率÷波特率÷3)
TL0=baud%256; //溢出率=定时器脉冲频率÷(65536-重载值)
TR0=1; //启动定时器,模拟串口开始工作
baud_index=index;
}
void respond_packge(void)
{
com_bit_tick=100;
while(com_bit_tick!=0);
DE_RE=1; //置75176为发送模式
checksum=0;
for(count=0;count<6;count++)
{
temp=zhen_tou;
send_byte(temp);
checksum=checksum+temp;
}
for(count=0;count<5;count++)
{
checksum=checksum+jie_shou;
}
jie_shou=checksum;
for(count=0;count<6;count++)
{
send_byte(jie_shou);
}
DE_RE=0; //置75176为接收模式
}
void execute_cmd(void)
{
if(jie_shou==0x00)//断开继电器命令
{
if(jie_shou==0x00){IO1=0;}//关闭一号继电器
if(jie_shou==0x01){IO2=0;}//关闭二号继电器
if(jie_shou==0x02){IO3=0;}//关闭三号继电器
if(jie_shou==0x01){respond_packge();}
}
if(jie_shou==0x01)//接通继电器命令
{
if(jie_shou==0x00){IO1=1;}//闭合一号继电器
if(jie_shou==0x01){IO2=1;}//闭合二号继电器
if(jie_shou==0x02){IO3=1;}//闭合三号继电器
if(jie_shou==0x01){respond_packge();}
}
if(jie_shou==0x02)//查询继电器命令
{
if(jie_shou==0x00){if(IO1==1){jie_shou=0x01;}else{jie_shou=0x00;}}
if(jie_shou==0x01){if(IO2==1){jie_shou=0x01;}else{jie_shou=0x00;}}
if(jie_shou==0x02){if(IO3==1){jie_shou=0x01;}else{jie_shou=0x00;}}
respond_packge();
}
//---------------------
if(jie_shou==0x03)//设置可控硅1亮度命令
{
brightness1=200-jie_shou;
traic_on_off();
if(jie_shou==0x01){respond_packge();}
}
if(jie_shou==0x04)//设置可控硅2亮度命令
{
brightness2=200-jie_shou;
traic_on_off();
if(jie_shou==0x01){respond_packge();}
}
//---------------------
if(jie_shou==0x05)//设置并保存可控硅1亮度命令
{
IO1=IO2=traic_1_on=traic_2_on=0;
brightness1=200-jie_shou;//计算亮度值
etmp1=read_eeprom(0x0201);//读出第二通道可控硅亮度值进行保护
erase_eeprom(0x0200);//擦除EEPROM
write_eeprom(0x0200,brightness1);//写入新的第一通道可控硅值
write_eeprom(0x0201,etmp1);//写回第二通道可控硅值
traic_on_off();//判断是否启用可控硅控制
if(jie_shou==0x01){respond_packge();}
}
if(jie_shou==0x06)//设置并保存可控硅2亮度命令
{
IO1=IO2=traic_1_on=traic_2_on=0;
brightness2=200-jie_shou;
etmp1=read_eeprom(0x0200);//读出第一通道可控硅亮度值进行保护
erase_eeprom(0x0200);//擦除EEPROM
write_eeprom(0x0201,brightness2);//写入新的第二通道可控硅值
write_eeprom(0x0200,etmp1);//写回第一通道可控硅值
traic_on_off();//判断是否启用可控硅控制
if(jie_shou==0x01){respond_packge();}
}
//---------------------
if(jie_shou==0x10)//断开继电器命令,为了兼容485继电器模块的命令
{
IO1=0;
if(jie_shou==0x01){respond_packge();}
}
if(jie_shou==0x11)//接通继电器命令,为了兼容485继电器模块的命令
{
IO1=1;
if(jie_shou==0x01){respond_packge();}
}
if(jie_shou==0x12)//查询继电器命令,为了兼容485继电器模块的命令
{
if(IO1==1)
{
jie_shou=0x01;
}
else
{
jie_shou=0x00;
}
respond_packge();
}
//---------------------
if(jie_shou==0x15)//查询从机地址
{
jie_shou=read_eeprom(0x0000);
jie_shou=~jie_shou;
respond_packge();
}
if(jie_shou==0x16)//修改从机地址
{
etmp2=read_eeprom(0x0001);
erase_eeprom(0x0000);
write_eeprom(0x0000,jie_shou);
write_eeprom(0x0001,etmp2);
zhen_tou=jie_shou;
zhen_tou=~jie_shou;
if(jie_shou==0x01){respond_packge();}
}
if(jie_shou==0x18)//查询从机波特率
{
jie_shou=read_eeprom(0x0001);
if(jie_shou>10)
{
jie_shou=5;
}
respond_packge();
}
if(jie_shou==0x17)//设置从机波特率
{
if(jie_shou>10)
{
jie_shou=5;
}
etmp1=read_eeprom(0x0000);
erase_eeprom(0x0000);
write_eeprom(0x0000,etmp1);
write_eeprom(0x0001,jie_shou);
set_baud(jie_shou);
if(jie_shou==0x01){respond_packge();}
}
}
void close_eeprom(void)
{
eeprom_cont=0;
eeprom_cmd=0;
eeprom_star=0;
eeprom_addh=0x80;
eeprom_addl=0x00;
}
unsigned char read_eeprom(unsigned int addr)
{
unsigned char dat;
eeprom_cont=0x81;
eeprom_cmd=1;
eeprom_addl=addr&0xff;
eeprom_addh=addr>>8;
eeprom_star=0x5a;
eeprom_star=0xa5;
_nop_();
_nop_();
_nop_();
dat=eeprom_data;
close_eeprom();
return(dat);
}
void write_eeprom(unsigned int addr,dat)
{
eeprom_cont=0x81;
eeprom_cmd=2;
eeprom_addl=addr&0xff;
eeprom_addh=addr>>8;
eeprom_data=dat;
eeprom_star=0x5a;
eeprom_star=0xa5;
_nop_();
_nop_();
_nop_();
close_eeprom();
}
void erase_eeprom(unsigned int addr)
{
eeprom_cont=0x81;
eeprom_cmd=3;
eeprom_addl=addr&0xff;
eeprom_addh=addr>>8;
eeprom_star=0x5a;
eeprom_star=0xa5;
_nop_();
_nop_();
_nop_();
close_eeprom();
}
void byte_reced(void)
{
if(bytereceived==1)
{
bytereceived=0;
if(data_receive_enable)
{
jie_shou=byte_received;
fr_num++;
if(fr_num>=6)
{
data_receive_enable=0;
fr_num=0;
if(pack_ana()==1)
{
execute_cmd();
}
}
}
else
{
if( (zhen_tou==byte_received) || (cast_tou==byte_received))
{
verify++;
if(verify>=6)
{
data_receive_enable=1;
verify=0;
}
}
else
{
verify=0;
data_receive_enable=0;
if(zhen_tou==byte_received)
{
verify=1;
}
}
}
//------------------------------------------------//
}
}
void traic_on_off(void)
{
if(brightness1>=200){brightness1=199;traic_1_on=0;}else{traic_1_on=1;}
if(brightness2>=200){brightness2=199;traic_2_on=0;}else{traic_2_on=1;}
if(traic_1_on==1 || traic_2_on==1){P3M0=0X36;}else{P3M0=0x3c;}
}
用RMB0.59的可以仿真的 STC8G1K08-36I-SOP8
最新数据手册下载
深圳国芯人工智能有限公司-产品_STC8G系列 (stcai.com)
页:
[1]