2017-11-01 23:15:37 wzz110011 阅读数 6388
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3452 人正在学习 去看看 张先凤
在MSP430单片机的官方历程中有使用串口中断发送字符以及字符串的程序,但是移植性不高,我专门写了两个函数,用于发送单个字符合字符串,不需要使用中断,供大家参考。
/**********************************************
*程序描述:单片机的P3.4、P3.5作为串口发送字符和字符串
*作者    :Zhenhua Liu
*时间    :2017.11.01  23:00
***********************************************/
#include "msp430x14x.h"
#define uchar unsigned char
uchar DATA[]="hello world my name!";
void sendString(unsigned char *p);
void sendChar(char c);
void uartInit(void);
void main()
{
  // Stop watchdog timer to prevent time out reset
        uchar *p;
        p=DATA;
        WDTCTL = WDTPW + WDTHOLD;
        uartInit();     //初始化串口P3.4和P.35
        sendChar('k');
        sendString(p);
          while(1);
}
/****************************************************************************
*函数名: sendChar()                                                          /
*作用  :USART0发送一个字符                                                  /
*返回值:无                                                                  /
*参数  :一个字符                                                            /
*作者  :Zhenhua Liu                                                         / 
*时间  :2017.11.01                                                          / 
*****************************************************************************/
void sendChar(char c){
   TXBUF0=c;
   while((UTCTL0&0X01)==0);//等待数据发送完毕 
}
/****************************************************************************
*函数名: sendString()                                                        /
*作用  :USART0发送字符串                                                    /
*返回值:无                                                                  /
*参数  :char型指针                                                          /
*作者  :Zhenhua Liu                                                         / 
*时间  :2017.11.01                                                          / 
*****************************************************************************/
void sendString(unsigned char *p){
  
   while(*p!='\0'){
            TXBUF0=*p++;
            while((UTCTL0&0X01)==0);//等待数据发送完毕   
          }
}
/****************************************************************************
*函数名: uartInit()                                                          /
*作用  :USART0的初始化配置,使用P3.4和P3.5,不使用中断                      /
*返回值:无                                                                  /
*参数  :无                                                                  /
*作者  :Zhenhua Liu                                                         / 
*时间  :2017.11.01                                                          / 
*****************************************************************************/
void uartInit(){
       P3DIR|=BIT4+BIT5;
        P3SEL|=BIT4+BIT5;
        
        ME1 |= UTXE0 + URXE0;  // 使能USART0收发
        UCTL0 |= CHAR;         // 8-bit 数据,一位停止位
        UTCTL0 |= SSEL0;       // 选择时钟,UCLK = ACLK,32768
        UBR00 = 0x03;          // 32k/9600
        UBR10 = 0x00;          //
        UMCTL0 = 0x4a;         // Modulation
        UCTL0 &= ~SWRST;       // 初始化UART0状态机,一般要设置好串口之后才复位      
}

2016-04-15 17:02:17 CB_869145753_hp 阅读数 30426
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3452 人正在学习 去看看 张先凤

在51单片机中,我们使用上下位机时,我们通常会发送一串字符串,将它作为信号发给单片机处理。

因为串口通信时,发送信息是以一个个字符的形式发送过来的,所以接收的就是一个个字符,通常我们是一个字符数组保存,在进行下一步处理,同时字符数组长度固定有限,但是如果上位机发送的字符不满足我们想要处理的数据时,其接收的数据多出的部分就有可能保存在SBUF中, 影响接下来的数据接收,以至于接下来的数据不满足我们的要求。或是发送数据少于数组长度时,也会出错。

在这里我的解决办法(以下以STC12C5A60S2芯片为例):

void serial_port_one_init()
{                       //根据自己单片机设置;

    //22.1184M   波特率: 115200
    SCON = 0x50; 
    BRT = 0xFA;
    AUXR |= 0x04;
    AUXR |= 0x01;
    AUXR |= 0x10;
   ES      =   1;    
   EA      =   1;    
}                   

#define Data_SIZE 10 //数据长度   9位数据 +  /r/n  -  /n =10位

char RevBuf[Data_SIZE];      //数据接收缓冲区
char temp[Data_SIZE];        //防数据抵消缓冲区
unsigned char flished_flag=0; //数据接收符合要求标志
int data_count=0;    //数据长度
int temp_length;    //数据长度
int data_flished_count = 0;  //
char data_flished;           //

void UART_one_Interrupt_Receive(void) interrupt 4
{  
    uchar temp;
  if(RI==1)
    {
        RI=0;
        temp=SBUF;
//        senduart(temp);  //用来测试过数据接收是否正确
        
        if(temp!='\n') //判断是否接收到结束符
        {
            RevBuf[data_count]=temp;// 否,就存到RevBuf【】数组中
            data_count++;
        }
        else
        {
            temp_length=data_count;//是,记录其数据长度
            data_count=0;
        }
        
    }
    
}             


void main(void)

{

    serial_port_one_init();  //串口初始化

   while(1)

    {

          if(Data_SIZE == temp_length)   //判断数据长度是否满足我们的要求。
        {
            for(i=0;i<Wifi_Data_SIZE;i++)
            {
                temp[i]=RevBuf[i];             // 同时我们将temp【】作为缓冲区,防止数据被冲到
            }
            flished_flag=1;          //数据接收成功标志
        }

      if(1==flished_flag)  //     数据接收完整成功
        {
            
            wifi_flished_flag=0;  //

           //

           //你想要实现的功能

/*

switch(temp[1]) //我常把数据第一位或前几位作为指令,后几位作为数据,你也可以把整个发送的数据就作为指令。

{

case 'A' :

//具体操作

break;

}

         */

        }

    }

  while(1);

}

同时某些特殊情况,我们会将数据写成:数据头+数据  

分析数据头,实现其代表的功能

上位机中 要在发送数据的最后加上 ‘/n’这个字符

用串口工具测试时, 发送数据为:数据+enter键(其代表的是两个字符 /r /n)



2016-01-03 11:12:13 aorangezzz 阅读数 1334
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3452 人正在学习 去看看 张先凤
/***********************************************************************************
*	标题:                  RS232串口通信试验                                        *          
*	功能:串口接收数据后打印,按回车键处理命令,通过数组储存命令				    *
*	      按 退格键 会准确地删除一位数据并清除串口的显示,尝试使用串口命令来清屏    *
*************************************************************************************/

#include <REG52.H>

sbit BEEP = P1^4;
sbit JDQ1 = P1^1;
sbit JDQ2 = P1^2;

bit Flag;
bit Flag_comm;
unsigned char ReData[5],SenData[5];	//接收数据缓存,发送数据缓存	,不指定大小会waring,应该是怕溢出
unsigned char serial_receive[64];   //接收命令的数组

static unsigned char coun = 0;

void serial_print(char *str){
	unsigned char i = 0;
	while(str[i] != '\0')
	{
		 SBUF = str[i];
		 while(!TI);
		 TI = 0;
		 i++;
	}
}

//串口初始化,初始化函数需要改进,修改为自动计算配置
void serial_init(){
	SCON = 0x50;      //REN=1允许串行接受状态,串口工作模式1    	       	   
	TMOD|= 0x20;      //定时器工作方式2                    
	PCON|= 0x80;                                                          
	TH1  = 0xFD;     //baud*2  /* reload value 19200、数据位8、停止位1。效验位无 (11.0592) 
	//	TH1 = 0xF3;					// //baud*2  /*  波特率4800、数据位8、停止位1。效验位无 (12M)
	TL1 = 0xF3;         
	TR1  = 1;                                                          
}

//主函数,串口接收完整指令后解析执行命令
void main (void) {
	serial_init();    //串口初始化要加入配置                                                     
	ES   = 1;        //开串口中断                  
	EA   = 1;        // 开总中断 

	serial_print("\n\rserial_init,waiting for input:\n\r");
	serial_print("common  input:");
	while(1)
    { 
		if(Flag_comm == 1){
			serial_print("\n\r");
			serial_print("receive common:");
			serial_print(serial_receive);
			serial_print("\n\r");
			//这里将传入参数进行命令解析
			//solve(serial_receive);
			serial_print("excuseing !!!!!!!!!!!!\n\r");
			serial_print("common  input:");
			coun = 0;   //打印后清零串口计数 
			Flag_comm = 0;	//处理命令后清除标志位
		}
 	}
}

/****************************************************
               串口中断程序
******************************************************/
void serial_interrupt (void) interrupt 4 using 1
{
	if(RI == 1)        //RI接受中断标志
	{
	 	RI = 0;		    //清除RI接受中断标志
		Flag=1;		    //接收到数据
		*ReData = SBUF;  //SUBF接受/发送缓冲器
		*SenData = *ReData;
		if( *ReData != 0x0d ){	   //等待接收回车
			if( *ReData == 0x08 ){	 //退格键
				serial_receive[--coun] = '\0';//遇到退格键要把刚刚的值清0,所以是--coun
				serial_print("\b ");               //覆盖掉原来的值
			}else{
				serial_receive[coun++] = *ReData;
			}
		}else{
			serial_receive[coun] = '\0';	 //遇到回车键,写\0,字符串终止
			Flag_comm = 1;					 //接收命令完成,解析命令
		}
	}
	if(Flag == 1){		 //接收到字符就打印,避免存在输入过快无法显示
		serial_print(SenData);
		Flag = 0;	
	}
}
//0x0d = \r 0x0a = \n	0x08 = \b


2014-03-31 21:50:51 u014030821 阅读数 21647
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3452 人正在学习 去看看 张先凤

这篇文章将说明51串口通信的发送与接收。分为:单个字符接收,字符串接收;十进制发送与接收,十六进制发送与接收。

字符串发送与十六进制发送,参考:http://blog.csdn.net/yibu_refresh/article/details/22695063

程序皆由PC串口工具发送,由单片机接收,并返回接收值给PC机。


一:单个字符的发送与接收

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
//定义接收 字符
uchar Buffer;

//串口初始化函数
void   URATinit( )
{
 TMOD=0x20;
 SCON=0x50;
 EA=1;
 ES=1;
 TR1=1;
 TH1=0xfd;
 TL1=0xfd;
}
//中断函数
void receive() interrupt 4
{
 if(RI)
 { 
  Buffer=SBUF;
  RI=0;
 }
 SBUF=Buffer;
 while(!TI);
 TI=0;
}
//主函数
void  main()
{
 URATinit( );
}
在中断函数中,如果接收到数据则RI由硬件置1,这时候把SBUF缓冲区的数据赋值给Buffer,并将RI置0,等待下次接收。同时,将接收到的数据再放入缓冲区,发送给PC机。当发送完毕的时候TI会被硬件置1,这时候需要将TI置0,以待下次发送。

运行效果:


发送数据1,则返回1。


二.字符串接收

(1)

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
//定义接收 数组
uchar Buffer[5]={0};
uchar i=0,j=0;

//串口初始化函数
void   URATinit( )
{
 TMOD=0x20;
 SCON=0x50;
 EA=1;
 ES=1;
 TR1=1;
 TH1=0xfd;
 TL1=0xfd;
}
//中断函数
void receive() interrupt 4
{
 if(RI)
 { 
  Buffer[i]=SBUF;
  RI=0;
 }
 SBUF=Buffer[i];
 while(!TI)	;
 TI=0;
 i++;
 if(i>=5){
 	i=0;
 }
}
//主函数
void  main()
{
 URATinit( );
}		 
在中断函数当中用Buffer[]接收收到的数据,同时将Buffer[]再发送给上位机。这里要注意变量i的定义。如果定义为全局变量则Buffer[0-5]都可以接收到数据,需要对i计数,防止大于5溢出。

运行效果:


(2)

#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
//定义接收 数组
uchar Buffer[5];
uchar i=0,flag;

//延时函数
delay(uint  ms)
{
 uchar i;
 while(ms--)
 for(i=0;i<123;i++);
}
//串口初始化函数
void   URATinit( )
{
 TMOD=0x20;
 SCON=0x50;
 EA=1;
 ES=1;
 TR1=1;
 TH1=0xfd;
 TL1=0xfd;
}
//中断函数
void receive() interrupt 4
{
 if(RI)
 { 
  Buffer[i++]=SBUF;
  RI=0;	 
  if(i>=5){
 	i=0;
 	}
  flag=1;
 }
}
//主函数
void  main()
{
 uchar k=0;
 for(k;k<5;k++){
 Buffer[k]=0;
 }
 URATinit( );
 while(1){
 if(flag) {
 	uchar j=0;
 	for(j;j<5;j++){
 		SBUF=Buffer[j];
 		while(!TI)	;
 		TI=0;
		delay(50);
 		}
 	flag=0;
	}
}
}		 
这时不是从中断函数中发送接收到的字符串,而是在主函数中发送接收到的字符串。于是需要flag标志位来判断是否接收到数据,并且用while(1)循环来不断判断并输出接收到的字符串。

运行效果:


其实方法(1)优于方法(2),现在来发送字符串"1234"与“123456”来看看效果:

发送“1234”(发送3次)


发送“123456”(发送3次):


可以看出(1)方法总是可以正确传输回并显示所发送的字符串,而(2)方法则有一定的局限性,只有当传输5个字符的字符串时才可以出现想要的显示效果。

分析发现:(1)中在中断中直接发出收到的字符,接收一个发送一个,为实时效果。(2)则在主程序中整体发送接收到的Buffer数组,例如接收“1234”,当“1234”发过来的时候由于Buffer为5位数组,因此第一次发送会给Buffer[0-3]赋值,Buffer[4]未赋值,返回给上位机第一次输出为“1234”,但第二次发送时候会给Buffer[4]赋值,同时溢出把i归为0。再次输出Buffer时造成了传输字符串的重叠与混乱。其实(1)也有这个现象,只是(1)的返回为及时返回。


三. 字符串发送与十六进制发送:

#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar num;

sbit dula=P2^6;		//申明U1锁存器的锁存端
sbit wela=P2^7;		//申明U2锁存器的锁存端

uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};

void delay(uint xms)				
{
	uint i,j;
	for(i=xms;i>0;i--)		      //i=xms即延时约xms毫秒
		for(j=110;j>0;j--);
}

void display(uint value)  //显示子函数
{
	uchar wan,qian,bai,shi,ge;   //定义万千百十个位
	wan=value/10000;               
	qian=value%10000/1000;
	bai=value%1000/100;		
	shi=value%100/10;
	ge=value%10;
	
	dula=1;
	P0=table[wan];    
	dula=0;
	P0=0xff;	
	wela=1;			
	P0=0xfe;		
	wela=0;
	delay(2);	  
	
	dula=1;
	P0=table[qian];
	dula=0;
	P0=0xff;
	wela=1;
	P0=0xfd;
	wela=0;
	delay(2);
	
	dula=1;
	P0=table[bai];
	dula=0;
	P0=0xff;
	wela=1;
	P0=0xfb;
	wela=0;
	delay(2);
	
	dula=1;
	P0=table[shi];
	dula=0;
	P0=0xff;
	wela=1;
	P0=0xf7;
	wela=0;
	delay(2);	
	
	dula=1;
	P0=table[ge];
	dula=0;
	P0=0xff;
	wela=1;
	P0=0xef;
	wela=0;
	delay(2);	
}

void init()         //初始化函数
{
	TMOD=0x20;      //设置定时器1工作方式
	TH1=0xfd;
	TL1=0xfd;
	TR1=1;
	SM0=0;
	SM1=1;
	REN=1;
	EA=1;
	ES=1;
}

void main()
{
    init();
	while(1)
	{
	    display(num);
	}
		
}

void ser() interrupt 4     //串口中断函数
{
	if(RI){
	   num=SBUF;          
       RI=0;
	   }              //置RI为0以便接收下一个数据
	   SBUF=num;
	   while(!TI);
	   TI=0;
}
这个程序可以在数码管上显示接收到的字符/数据,同时将接收到的数据返回给上位机显示。

先发送字符‘a’,即默认的字符串发送方式:


发送字符‘a’,这时单片机返回给上位机的也为‘a’(默认的字符串显示方式)。但是数码却显示97,为‘a’的ASCII码。这说明在传输过程中,始终为ASCII码传输。数码管之所以没显示‘a’,因为数码管为十进制显示方式,故显示97。(‘a’(ASCII显示)——>97(十进制显示)——>'a'(ASCII码显示))

发送字符‘a’,选择16进制发送,16进制显示:


这时发送端为16进制‘a’,即10进制的10。数码管显示10,而返回的值用16制显示为0A。

由文章开始的参考文章知道16进制发送时每次发送两位数据,如:发送十进制20,即16进制的14,这时数码管会显示20。(14(16进制显示)——>20(10进制显示)——>14(16进制显示))。


2018-07-10 11:42:09 ABC13222880223 阅读数 572
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3452 人正在学习 去看看 张先凤

字符串转int atoi

函数原型int atoi(const char *nptr);

int val = atoi("12");
这样va就l等于12

int转字符串 itoa
函数原型:char*itoa(intvalue,char*string,intradix);
int number=123456;
char string[25];
itoa(number,string,10);
string就是123456 后面的10是说转化成10进制 16就是转化成16进制 8就是转化成8进制 ,也可以转化成2进制

字符串截取 strncpy
原型:char*strncpy(char*dest,char*src,size_tnum);
大家知道strcpy 是子环节复制字符串,可能不知道还有个strncpy,这是复制指定长度的字符串
chardes[]="Hello,iam!";
charsource[]="abcdefg";
strncpy(chardes,charsource,3);
这时chardes的值是abc 注意这里可不是把abc添加在!后面的,是从chardes这个数组的首地址开始赋值的,最后会加上'\0'做结束符。
改变一下用法
strncpy(chardes+1,charsource+2,3);
这时候chardes的值是Hcde 为什么是这个值,能看懂不?自己思考一下。偏移哈。

字符串构造 sprintf
原型 int sprintf( char *buffer, const char *format, [ argument] … );
这个应该很多人都知道。
char dest[20];
int val=12;
sprintf(dest,"val=%d",val);

dest的值就是"val=12" 那个12也是字符串了哈注意下。
这个函数也可以整形、浮点型转字符串
sprintf(dest,"%f",3.1415926f);
dest 就是“3.1415926”

sprintf(dest,"现在的时间是%s,请注意","2014-04-09 11:27:21"); 后面这个字符串也可以换成变量
dest的值是 "现在的时间是2014-04-09 11:27:21,请注意"

直接对内存操作memset
原型 void *memset(void *s, int ch, size_t n);
char buffer[20];
strcpy(buffer,"1234567890");
memset(buffer,0,sizeof(char)*20);
这时buffer中的数据全都是0了

strcpy(buffer,"1234567890");
memset(buffer+2,6,sizeof(char)*2);
这时buffer值是1266567890
这个函数可以对任何数据类型的内存进行修改。所以有些从串口接收进来的数据需要做一下简单的修改再转发出去的话就可以用这个函数做修改。

先介绍这些吧,再想起来别的再补充
【2014-04-11 补】

memcpy函数使用起来也不错的,直接把字节数组复制到指定位置了,这个就不说了。

字符串分割strtok
原型 char *strtok(char s[], const char *delim);
分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。

ARDUINO 代码

 
输出:
abc
d

记住了,只要第一次分割的时候需要指定字符串,之后再分割就用NULL就行了,当p==NULL的时候说明分割完了。这里使用到了指针,此处指针不需要释放。


查找字符串 strstr
原型 char *strstr(const char *str1, const char *str2);
strstr() 函数搜索一个字符串在另一个字符串中的第一次出现。
str1: 被查找目标 
str2: 要查找对象 

char str[]="1234 xyz";
char* str1=strstr(str,"34");
printf("%s",str1);
显示: 34 xyz

字符串比较 strcmp
原型:extern int strcmp(const char *s1,const char * s2);
比较s1和s2 两个相等就返回0 不想等就返回非0值。

字符串连接strcat
原型 extern char *strcat(char *dest,char *src);
把src 连接到dest值的后面,注意dest要有足够的空间去接收src否则会出错

 

没有更多推荐了,返回首页