jackduan 发表于 2025-2-13 10:12:17

格雷码与二进制转换

这个程序格雷码转二进制的部分当时没看明白,总觉得和二进制转格雷码的代码功能一样。
其实没看明白while(x>>1)这条语句的功能。
这条语句是把x按位右移1位,直到x值为0时跳出循环。

#include“STC15W4K.H”
#include<stdio.h>                                             /*为使用printf函数而加入*/
unsigned long decimaltogray(unsigned long x)      //自然二进制码转换成格雷码
{
return x^(x>>1);
}

unsigned long graytodecimal(unsigned long x)      //格雷码转换成二进制
{
unsigned long y= x;
while(x>>=1)
{
    y^=x;
}
return y;
}

viod main()
{
unsigned long i,x,y;
TI=1;                                    //软件调试的串行窗口与波特率无关,只要TI=1即可
for(i=0;i <1000;i++)
{
    x=decimaltogray(i);
    printf("格雷码:%1d",x);
   
    y=graytodecimal(x);
    printf("十进制:%1d\n",y);
}
while(1);
}


以十进制8(二进制1000)为例进行程序中的运算过程演示:
二进制转换成格雷码:
1000>>1=0100;
1000^0100=1100;
计算结束,计算结果为1100,即8的格雷码为:1100。

格雷码转换成二进制:
1100>>1=0110;
1100^0110=1010;
y=1010,x=0110;

0110>>1=0011;
1010^0011=1001;
y=1001,x=0011;

0011>>1=0001;
1001^0001=1000;
y=1000,x=0001;

0001>>1=0;
x=0;
跳出while()函数。

计算结束计算结果为y=1000,即格雷码1100转换为二进制1000。

程序虽小,看不明白还是看不明白,看不明白的就要弄明白,再小也得弄明白,否则到处都时不明白。

jackduan 发表于 2025-2-13 13:56:39

以上程序串口助手里没有显示内容,加串口初始化函数后有内容,但是串口接收的内容和程序语句描述的不一样。

这是测试的结果

和理论结果有差别

jackduan 发表于 2025-2-14 09:32:22

很久才整明白的语句

    unsigned char a;
    //a=0;
    port_mode();            // 将单片机所有端口配置为准双向弱上拉方式
        while(1)       
        {
                P0 =~(1<<a++);                  // 第一次运行时 0000 0001<< 0 = 0000 0001
                //a++;
                //P0=~(1<<a);
                //a++;
           if (a==0x08)          // 允许左移8次。
                {
                        a=0;
                }
      }
这是一个流水灯的程序,其中P0 =~(1<<a++);这条语句我看了很久才弄明白。
1.困惑的是运算顺序 a应该先++,还是应该先位移?
通过语句分解和实验证明a是先进行左移运算,后进行自加运算的。
如果a先进行自加运算P0.0这个灯会一直不亮。被抛弃了。至于为什么会被抛弃,我在思考的这个阶段还没特别明白,能想到的就是那一位被抛弃了。
2.其次是1<<a,这条语句我一直理解为a左移了1位,其实是1左移了a位。弄明白这个语句就不难理解为什么P0.0会被抛弃了。a先自加1,a==1,1左移1位=0000 0010,再取反=1111 1101,P0.0位一直会是1(低电平导通),所以P0.0一直不亮。
3.为什么没有对a进行赋初值,那初值会是多少?是0吗?
经测试a的初值可以是0。但是a赋值大于8的时候灯就不会亮,因为if (a==0x08)时a=0,这里改成a> =0x08,a就可以是大于8的值。可是原程序a==0x08,a不赋初值也都可以运行,那a是怎么保证不大于8的?

jackduan 发表于 2025-2-15 16:15:38

模拟串口

通过编写程序控制单片机的普通IO口也能实现串口通信,称为模拟串口。
对于没有串口的廉价型单片机,通过使用模拟串口也能实现最基本的串口通信功能,不足之处在于数据发送与接收不能同时进行。
软件设计中,接口程序主要由sendbyte()发送函数和recvbyte()接收函数组成。
发送时先发送一个起始位(低电平),接着按低位在前的顺序发送8位数据,最后发送停止位。
接收时先判断P3.3接收端口是否有起始位低电平出现,如有则按照低位在前的顺序接收8位数据,最后判断是否有停止位高电平出现,如有则完成一个字节的接收,否则继续等待。
其中软件编写要严格按照异步通信的时序进行,每位传送时间按通信速率9600bps计算为(1/9600)s=104.2us。

#include"STC15W4K.H"
#define RECEIVE_MAX_BUTES   1       //最大接收字节数
unsigned char RecvBuf;                   //接收数据缓冲区
unsigned char RecvCount=0;               //接收数据计数器
sbit T_TXD=P3^2;                               //发送数据引脚
sbit R_RXD=P3^3;                               //接收数据引脚
bit RXD_OK;                                        //数据接收完成标志,1接收正确 ,0接收错误

void delay104us()
{
   unsigned char i,j,k;
   for(i=1;i>0;i--)         // 注意后面没分号
   for(j=3;j>0;j--)         // 注意后面没分号
   for(k=189;k>0;k--);      // 注意后面有分号
}
void delay52uS()                                    // 起始位结束后52uS采样数据
{
   unsigned char i,j,k;
   for(i=1;i>0;i--)         // 注意后面没分号
   for(j=3;j>0;j--)         // 注意后面没分号
   for(k=93;k>0;k--);       // 注意后面有分号
}
voidsenbyte(unsigned char dat)
{
unsigned char i=8;      //发送8位数据
T_TXD =0;                   //发送起始位
delay104us();      
while(i--)
{
    if(dat&1)T_TXD=1;
    else T_TXD=0;
    delay104us();
    dat>>=1;
}
T_TXD=1;                     //发送停止位
delay104us();
}

unsigned char recvbyte()
{
unsigned char i;
unsigned char dat=0;             //接收到的数据
RXD_OK=0;                        //字节数据接收正常标志位
delay52us();                         //数据位中心位置读取数据
if(R_RXD==0)                      //确认起始位正常
{
    delay104us();                     //起始位宽度
    for(i=0;i<8;i++)
    {
      if(R_RXD)dat|=(1<<i);
      delay104us();
    }
    if(R_RXD==1)                //确认停止位正常
    {
      RXD_OK=1;
    }
}
return dat;
}

void printfstr(char *pstr)      //串口打印字符串
{
while(*pstr)
{
    sendbyte(*pstr++);
}
}
void main(void)
{
unsigned char i;
printfstr("模串口:STC15\r\n");
while(1)
{
    if(R_RXD==0)                                             //不断检测是否有起始位出现
    {
    recvbuf=recvbyte();
      if(RXD_OK ==1)                                          //一个字节接收正常
      {
      recvcount++;
      if(recvcount>=RECEIVE_MAX_BYTES)
      {
          recvcount=0;
          for(i=0;i<RECEIVE_MAX_BYTES;i++)
      {
          sendbyte( RecvBuf+1);                           //接收到的数据+1后发回
      }
      }
      }
    }
}
}

MZJ 发表于 2025-4-19 23:09:45

有没有搞到试验箱{:4_165:}

jackduan 发表于 2025-4-21 11:21:14

MZJ 发表于 2025-4-19 23:09
有没有搞到试验箱

有啊 你加油
页: 1 2 3 [4]
查看完整版本: 擎天柱 学习记录