Working with bits

I'm working on a project which includes some LCD display and PS/2 keyboard and a microcontroller. Im studying examples on the web and this is a bit of code I dont understand:

Code:

keyIn = keyIn >> 1;
if (pinIn)
{
keyIn = keyIn | 0x80;
}
break;

the keyin should be in the end the scan code of the pressed key, but i don't understand the process of making it so... pinin should be the input pin of the mcu which is connected to the keyboard data flow

What part do you not understand? Do you understand what shifting is? Do you understand what ORing is? Do you understand bit-wise operations in C?

You also left out what I can only assume is the loop that this code snippet was lifted out of. As well as the declaration of keyIn and its initial value. Therefore, I will assume that keyIn is an unsigned char that is initialized to zero (ie, '\x00'). I will furthermore assume that a serial input bit stream is attached to the input pin and that that incoming bit stream is most significant bit (MSB) first.

You initialize keyIn to zero and loop 8 times. First you shift all the bits to the right by one ( >> 1) in order to make room for the next incoming bit. What gets shifted in is a zero. Then you test the level on the pinIn input, which would be the next bit (I also assume some kind of time delay to ensure that each time you hit that if-statement then it's the next bit and you're not just re-testing the same bit as the last time). If that bit is a 1, then you set the MSB of keyIn to 1 ( | 0x80). Of course, if that bit is zero, then you don't do anything since the MSB is already set to zero.

Thank you very much for that comprehensive answer, it all seems much clearer to me! The last question I have on this particular topic - how do I recognize the start/parity/stop bitin every scan code sentence? I know it does not much belong into this topic, but I hungrily want to know this :)

- how do I recognize the start/parity/stop bitin every scan code sentence?

That all depends on the serial protocol and the serial port settings. Those settings could include transmission rates (AKA "baud rate"), type of parity, number of data bits, number of stop bits, all depending on that particular serial protocol -- see Serial Port: Settings.

Back in the late 1980's, I wrote assembly code for a low-powered Intel processor, ¿8749? (it's been a few decades, after all), which was coincidentally of the same family as the microprocessor in the original IBM/PC keyboards. Our devices communicated via an RS-232 serial port. Normally, you would use a separate hardware device called a UART to receive and send RS-232 serial streams and convert between the serial stream waveform and bytes of data; in some microprocessors a UART is built in. But to cut down on the size and cost of our devices (sensors and controllers for greenhouses), we did it all in software. It's been a long time, but here's a brief explanation from memory. Bear in mind that this is for one particular implementation of RS-232, often called the "non-standard standard" because of a wide number of variants; your own serial protocol may very well be quite different:

A character wave-form consists of the following parts in this order:
1. The "mark hold".
2. The start bit.
3. Several data bits (though a fixed number of them, depending on the settings). Note that normally with RS-232 we would receive the least significant bit first (LSB), on contrast to your protocol which receives the MSB first.
4. Optional parity bit, depending on the settings.
5. 1 to 2 stop bits, depending on the settings.
6. Reinstatement of the mark hold.

Characters are sent asynchronously, meaning that the next character could arrive unannounced at any time. The signal level between characters is a constant high (1) and is called a "mark hold". When the signal drops from the mark hold to a zero, then that marks the beginning of the start bit. Since you know beforehand what the baud rate is, you know how wide each bit is in terms of time. One bit-width later will be the start of the first data bit. What you want to do to read each data bit is to wait until the middle of the bit; that way you ensure that you are reading that bit and only that bit. Furthermore, you read it at least three times and then "take a vote" in order to prevent false values due to noise or other factors. Then you wait a full bit width for the next data bit and so on until all the data bits have been read. The number of data bits will depend on the settings. Then if you are using parity, you will read the parity bit the same way you read the data bits. Finally, you get to the stop bits. Some devices, especially electromechanical teletypes, rely on the stop bits, but our devices did not so we just merely observed that they were present and marked their passage. Then the signal level returns back to the mark hold.

One thing to note is that timing is critical. My microprocessor had a defined clock speed and each machine instruction had a defined number of clock cycles that it would take to execute, so I could, and did, read through a series of machine instructions and calculate exactly how long they would all take to execute. I needed to do that in order to obtain the timing needed to mark out each bit width. And whenever I had to perform a conditional jump, which was often (an industry average that we were taught in school was that on average one instruction in four is a jump), I had to trace through both branches of that jump to ensure that they were both of exactly the same length time-wise -- I would have to insert however many NOP instructions as were needed to pad that out. Please also note that the only reason I was able to do that was because I was working in assembly. It would have been impossible to do that with C or any other higher-level language (our host computer ran a Pascal program to communicate with the devices), since you have no control over the assembly code that a compiler would emit.

Again, your mileage with your own particular serial protocol and your own particular microprocessor may vary.