历史上的今天
返回首页

历史上的今天

今天是:2025年01月21日(星期二)

正在发生

2020年01月21日 | 51单片机IO口模拟UART串口通信

2020-01-21 来源:eefocus

#include
#include "main.h"
#include "smartcard.h"
#include "stdio.h"

typedef enum { false, true }bool;

#if 0
sbit PIN_RXD = P1^0; //接收发送同一个引脚定义
sbit PIN_TXD = P1^0; //接收发送同一个发送引脚定义
sbit PIN_CLK = P3^1; //智能卡时钟引脚定义
sbit PIN_3v5v = P3^2; //智能卡3v_5v引脚定义
sbit PIN_RST = P3^3; //智能卡复位引脚定义
sbit PIN_CMDVCC = P3^4; //智能卡CMD引脚定义
#else
// test Parity
sbit PIN_RXD = P1^0; //接收 脚定义
sbit PIN_TXD = P1^2; //发送 脚定义
sbit PIN_CLK = P3^5; //智能卡时钟引脚定义
sbit PIN_3v5v = P3^2; //智能卡3v_5v引脚定义
sbit PIN_RST = P3^3; //智能卡复位引脚定义
sbit PIN_CMDVCC = P3^4; //智能卡CMD引脚定义

sbit Test_CLK = P0^3; //接收 脚定义

 

#endif

bit RxdOrTxd = 0; //指示当前状态为接收还是发送
bit RxdEnd = 0; //接收结束标志
bit TxdEnd = 0; //发送结束标志
uint8_t RxdBuf = 0; //接收缓冲器
uint8_t TxdBuf = 0; //发送缓冲器
void ConfigUART(unsigned int baud);
void StartTXD(unsigned char dat);
void StartRXD();
void test_IO();

//通过嵌套宏定义,制作一张包括0~255各个数字中包含1的个数,其中包含偶数个1,则ParityTable256[i]=0,否则ParityTable256[i]=1;


static const bool ParityTable256[256] = 
{
#define P2(n) n, n^1, n^1, n
#define P4(n) P2(n), P2(n^1), P2(n^1), P2(n)
#define P6(n) P4(n), P4(n^1), P4(n^1), P4(n)
P6(0), P6(1), P6(1), P6(0)
};


void mainb(){
EA = 1; //开总中断
ConfigUART(9600);//配置波特率为 9600
while (1){ 
while (PIN_RXD); //等待接收引脚出现低电平,即起始位
StartRXD(); //启动接收
while (!RxdEnd); //等待接收完成
StartTXD(RxdBuf+1); //接收到的数据+1 后,发送回去
while (!TxdEnd); //等待发送完成
}
return;
}

void SET_3v5v()
{
PIN_3v5v=1;
}
void RESET_3v5v()
{
PIN_3v5v=0;
}

void RST_SET(BitAction ResetState)
{

PIN_RST = ResetState;
}

void SET_CMVCC()
{
PIN_CMDVCC =1;
}
void RESET_CMVCC()
{
PIN_CMDVCC =0;
}

/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud){
TMOD &= 0xF0; //清零 T0 的控制位
TMOD |= 0x02; //配置 T0 为模式 2
// TH0 = 256 - (11059200/6)/baud; //计算 T0 重载值
TH0 = 256 - (FOSC/12)/baud; //计算 T0 重载值

}
/* 启动串行接收 */
void StartRXD(){


while (PIN_RXD);
//printf("PIN_RXD2=0x%02Xrn", (int)PIN_RXD);
TL0 = 256 - ((256-TH0)>>1); //接收启动时的 T0 定时为半个波特率周期
ET0 = 1; //使能 T0 中断
TR0 = 1; //启动 T0
RxdEnd = 0; //清零接收结束标志
RxdOrTxd = 0; //设置当前状态为接收

}
/* 启动串行发送,dat-待发送字节数据 */
void StartTXD(uint8_t dat){
TxdBuf = dat; //待发送数据保存到发送缓冲器
TL0 = TH0; //T0 计数初值为重载值
ET0 = 1; //使能 T0 中断
TR0 = 1; //启动 T0
PIN_TXD = 0; //发送起始位
TxdEnd = 0; //清零发送结束标志
RxdOrTxd = 1; //设置当前状态为发送
}

uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
{
/* Check the parameters */
// assert_param(IS_USART_ALL_PERIPH(USARTx));

/* Receive Data */
#if 0
uint16_t tt= USARTx->SR ;
USARTx->SR = tt & (uint16_t)0x3df; //wuhh add ,remove later

return (uint16_t)(USARTx->DR & (uint16_t)0x01FF);
#endif
return (uint16_t) RxdBuf;

}
void USART_SendData(USART_TypeDef* USARTx, uint8_t Data)
{
StartTXD(Data);
}
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
{
FlagStatus bitstatus = RESET; 
if (USART_FLAG== USART_FLAG_TC)
if (TxdEnd)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}

if (USART_FLAG== USART_FLAG_RXNE)
if (RxdEnd)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
return bitstatus;
}
static bit polarity = 0; //输出智能卡时钟极性

#if 1

/* T0 中断服务函数,处理串行发送和接收 */
void InterruptTimer0() interrupt 1{

static unsigned char cnt = 0; //位接收或发送计数
Test_CLK = !Test_CLK;

if (RxdOrTxd)
{ //串行发送处理
cnt++;
if (cnt <= 8){ //低位在先依次发送 8bit 数据位
PIN_TXD = TxdBuf & 0x01;
TxdBuf >>= 1;
}else
if (cnt == 9)
{ //发送停止位
PIN_TXD = 1;
}
else{ //发送结束
cnt = 0; //复位 bit 计数器
TR0 = 0; //关闭 T0
TxdEnd = 1; //置发送结束标志
}
}
else{ //串行接收处理
if (cnt == 0){ //处理起始位
if (!PIN_RXD){ //起始位为 0 时,清零接收缓冲器,准备接收数据位
RxdBuf = 0;
cnt++;
}
else{ //起始位不为 0 时,中止接收
TR0 = 0; //关闭 T0
}
}else if (cnt <= 8){ //处理 8 位数据位
RxdBuf >>= 1; //低位在先,所以将之前接收的位向右移
//接收脚为 1 时,缓冲器最高位置 1,
//而为 0 时不处理即仍保持移位后的 0
if (PIN_RXD){
RxdBuf |= 0x80;
}
cnt++;
}else{ //停止位处理
cnt = 0; //复位 bit 计数器
TR0 = 0; //关闭 T0
if (PIN_RXD){ //停止位为 1 时,方能认为数据有效
RxdEnd = 1; //置接收结束标志
}
}
}
}

#else
/* T0 中断服务函数,处理串行发送和接收 */

void InterruptTimer0() interrupt 1{

static unsigned char cnt = 0; //位接收或发送计数 
//test_IO();
#if 0
PIN_TXD = !PIN_TXD;
#else

if (RxdOrTxd){ //串行发送处理
cnt++;
if (cnt <= 8){ //低位在先依次发送 8bit 数据位
PIN_TXD = TxdBuf & 0x01;
TxdBuf >>= 1;
}else if (cnt == 9){ //奇偶位
PIN_TXD=ParityTable256[TxdBuf]; 
}else if (cnt == 10){ //发送停止位1 智能卡协议共两个停止位
PIN_TXD = 1;
}else if (cnt == 11){ //发送停止位2 
PIN_TXD = 1;
}else{ //发送结束
cnt = 0; //复位 bit 计数器
TR0 = 0; //关闭 T0
TxdEnd = 1; //置发送结束标志
}
}else{ //串行接收处理
if (cnt == 0){ //处理起始位
if (!PIN_RXD){ //起始位为 0 时,清零接收缓冲器,准备接收数据位
RxdBuf = 0;
cnt++; 
//printf("InterruptTimer 0n");
} else{ //起始位不为 0 时,中止接收
TR0 = 0; //关闭 T0
printf("InterruptTimer closen");
}
}
else if (cnt <= 8){ //处理 8 位数据位
RxdBuf >>= 1; //低位在先,所以将之前接收的位向右移
//接收脚为 1 时,缓冲器最高位置 1,
//而为 0 时不处理即仍保持移位后的 0
if (PIN_RXD){
RxdBuf |= 0x80;
}
printf("RxdBuf=0x%02Xrn", (int)RxdBuf);
cnt++;
}else{ //停止位处理
cnt = 0; //复位 bit 计数器
TR0 = 0; //关闭 T0
if (PIN_RXD){ //停止位为 1 时,方能认为数据有效
RxdEnd = 1; //置接收结束标志
}
}
}
#endif
}
#endif

推荐阅读

史海拾趣

EXCELSEMI [ EXCEL SEMICONDUCTOR INC. ]公司的发展小趣事

EXCELSEMI公司始终将品质和客户满意度放在首位。公司建立了一套完善的质量管理体系和客户服务体系,确保每一款产品都符合高标准的质量要求。同时,公司还注重与客户的沟通和反馈,不断优化产品和服务以满足客户的需求。这种品质至上、客户为本的经营理念使得EXCELSEMI在市场中赢得了良好的口碑和信任。

American Electric公司的发展小趣事

随着技术的不断进步和市场的不断变化,American Electric公司意识到技术创新是保持竞争力的关键。因此,公司加大了对研发的投入,引进了一批高端技术人才,不断推出具有创新性的电力产品和服务。同时,公司还积极拓展业务,与多个大型企业建立合作关系,为其提供定制化的电力解决方案。这些举措不仅提高了公司的市场份额,还进一步提升了公司的品牌形象。

AK-Nord_GmbH公司的发展小趣事

为了确保产品质量和客户满意度,AK-Nord_GmbH投入大量资源建设质量管理体系。公司引入了国际先进的质量管理标准和流程,对产品的研发、生产、测试等各个环节进行严格把控。同时,公司还建立了完善的客户服务体系,及时响应客户需求和处理问题。这些举措有效提升了公司的产品质量和客户满意度,为公司赢得了良好的口碑。

Amphenol Thermometrics公司的发展小趣事

AK-Nord_GmbH公司自成立之初,便以技术创新为核心竞争力。在公司发展的早期阶段,团队研发出了一款具有革命性的电源管理芯片,该芯片以其高效能和稳定性迅速赢得了市场的认可。随着技术的不断完善和迭代,公司逐渐在电源管理领域树立了领先地位。随后,AK-Nord_GmbH又投入大量资源进行无线通信技术的研发,成功推出了一系列高性能的无线通信模块,进一步巩固了其在电子行业中的地位。

Electroswitch公司的发展小趣事

面对快速变化的电子行业环境,Electroswitch始终保持着敏锐的洞察力和创新精神。公司不断加大对新技术和新产品的研发力度,推出了一系列具有领先水平的开关产品。同时,公司还积极探索新的业务领域和市场机会,为未来的发展做好充分准备。展望未来,Electroswitch将继续秉承“质量、选择、产品创新和出色的支持”的理念,为客户提供更加优质的产品和服务。

请注意,以上故事框架仅供参考,您可以根据这些框架进一步扩展和丰富故事内容。

E-T-A [E-T-A Circuit Breakers]公司的发展小趣事

E-T-A公司的前身可以追溯到1948年,当时由Jakob Ellenberger和Harald A. Poensgen在德国共同创立了ELPO GmbH公司。这家初创企业专注于电气设备的研发和生产。随着技术的不断发展和市场的日益扩大,公司逐渐意识到设备用断路器在电路保护领域的重要性。因此,在1953年,公司正式推出了设备用的ETA断路器,并开始逐渐将重心转移到断路器领域,这也为日后E-T-A公司的成立奠定了基础。

问答坊 | AI 解惑

再议Linux与WinCE

Linux是单体内核,即将图形、驱动及文件系统等功能全在操作系统内核中实现,运行在内核状态和同一地址空间,其优点是减少了进程间通信和状态切换的系统开销,获得较高的运行效率;缺点是内核比较庞大! WinCE是微内核,即在内核中实现基本功能, ...…

查看全部问答>

ad783怎么用?

本帖最后由 paulhyde 于 2014-9-15 09:40 编辑 我实在是不知道这个东东怎么用啊,大家帮一下我吧!  …

查看全部问答>

AVR辅助开发工具

有助于写显示驱动和通信程序…

查看全部问答>

请问这个是怎么理解的设置定时器定时时间

void vSetMotorTimer(unsigned short uiTime)// uiTime us   {      RCAP2LH = uiTime;  }  //重新载入定时数据   void vUpdateMotorTimer(void)  {      T2LH=RCAP2L ...…

查看全部问答>

有没有人研究过mini2440的BSP,其BSP是如何识别128M/256M等flash的?

因为我使用的是QQ2440,但是我发现最新的mini2440的BSP更新了很多驱动,我想移进去QQ2440使用,但是可惜烧写进去后不能启动。 我觉得想搞好这个bsp必须先知道如何使用其他flash时需要修改的代码,哪位高手知道的,麻烦指导下。…

查看全部问答>

求介绍一些wince编程书籍

求介绍一些wince编程书籍…

查看全部问答>

C#如何捕获inputPanel输入法改变的事件

我是初学,最近被此问题困扰了好多天, 打开inputPanel后,改变输入法,inputPanel的高度会改变,此时如何捕获该事件。 我使用C#,开发环境vs   2005,.net   CF   2.0。 希望解释能详细些,我是初学。 还有我的 ...…

查看全部问答>

PG128128A资料

研究了N就,PG128128A资料到底怎么驱动,谁有能提供详细资料 12864及以下的我会,就是不会PG128128A的 邮箱 zoujun224@qq.com…

查看全部问答>

惭愧啊,st网站上想找点东西太难了

                                 也不知道是自己笨还是网站不太合理,反正在他官网上从来都没找到自己想要的东西,搜到的许多野都是指向其官网,可 ...…

查看全部问答>

DSP2812 5V和3.3V接口电压转换芯片

请教大家有没有用过 5V和3.3V接口电压转换芯片,我需要DSP2812外接DS18B20和其他几个5V峰值的转速信号,需要做电平转换,但是不知道使用什么样的接口电压转换芯片,需要方向控制的就不要介绍了,比如:SN74LVC164245。我需要的是自动双向转换电平的 ...…

查看全部问答>