Yes, what Wouter said. There are three parts to consider in designing a PIC programmer, the hardware, firmware, and software. There are a number of choices to make in each, and complexity can be traded off between them in various ways, especially between the firmware and the software.
For simple hardware that only addresses a subset of PICs, see my LProg programmer. This was optimized for low cost while still using a common PC interface the standard way. It only works with those PICs that don't require a high voltage on MCLR to enter programming mode, and all its signals are fixed 0-3.3 V. These two restriction allowed the hardware to be simple and the cost therefore lower. The schematic is available from the bottom of that page.
At the other end are the USBProg and USBProg2 programmers. Again, the schematics are available at the bottom of those pages. These have fully variable Vpp up to 15 V and the digital signals up to 6 V. They also have more protection. For example, the digital outputs can be shorted to anywhere from 0-6 V indefinitely without damage to the programmer. Of course all this complexity comes at a higher parts and manufacturing cost.
The software/firmware tradeoff is mostly a matter of firmware complexity versus speed. In theory you could make a programmer that only has facilities for the host software to set the lines to particular levels. The PIC programming protocol is synchronous, so all the clocking could be done in software. This would make the firmware simple to write, but the result would be a very slow programmer. Implementing the details of all the different programming algorithms Microchip has dreamed up over the years would take more program memory than is a available in most reasonable control PICs. The engineers at Microchip's Programming Obfuscation Division have been very busy. As Wouter said, there can be programming algorithm differences between PICs that otherwise appear to be very similar. You have to read the programming spec carefully for every PIC you intend to support. There is no one programming algorithm, not even close.
The host protocol to my programmers is linked to from all of the pages I mentioned above. This protocol was designed not just for the immediate task I had at hand, but to allow some latitude in programmer design. As a result, I pushed some complexity to the host software so that a variety of programmers with different native capabilities can be seamlessly supported. The same host program drives the LProg, USBProg, and some older programmers we have meanwhile discontinued. It does this not by checking which model it is talking to, but by inquiring its capabilities in a general way as defined by the protocol.
Making your own PIC programmer as a one-off for a specific PIC isn't too hard. Trying to make a general purpose PIC programmer is more difficult, probably a lot more difficult, than most people realize. If do end up making your own, I suggest you have it support my host protocol. If you look at the protocol carefully, you will see much of it is optional. If your programmer uses my host protocol, then you have my existing host code available for testing and possibly even for regular operation. Much of my source code is available from http://www.embedinc.com/picprg/sw.htm.
Well, I don't see anything explicitly wrong with what you are doing in your circuit with Vref = 0. But there are some concerns. Looking at the datasheet for the MCP6N11, nowhere do they ever set Vref to zero. All of the specified performance is for Vref = Vdd/2, or Vref = 0.75Vdd, or Vref = 0.25Vdd. None of the sample application circuits show Vref=0. Although the limits for Vref are stated as between \$V_ {\text {IVL}}\$ and\$V_ {\text {IVH}}\$, I could find no spec or example where they got outside 0.25Vdd or 0.75Vdd. It is suspicious.
I wonder why you use the 33 kOhm and 10 kOhm dividers on the inputs. Is the battery voltage larger than Vdd, and you are trying to keep the common mode voltage (Vcm) within spec? Usually one of the advantages of using a instrumentation amp is not having to use dividers. The problem is that tolerances add up quickly, and usually 1% resistors are not good enough to give adequate performance. For example if Vbat = 10V, 1% resistors could give an input voltage variation of +/-36mV. With a gain of 100 this could easily put you with an output voltage below Vref.
So, if you are going to or have to use dividers on the input it is crucial that they be very tight tolerance, or trimmed for tracking. You can find special parts like this (tight tolerance and trimmed), but they are somewhat special items. For a trimmed part with 0.1% tolerance and 0.01% tracking, you might spend $2 per divider.
Best Answer
I don't think there's a good way to do it. My first suggestion would be to just add a jumper in front of the LM282:
simulate this circuit – Schematic created using CircuitLab
The jumper (or DIP-switch) should be closed during normal operations and open when programming.
If you absolutely cannot live with this requirement for manual intervention, you may throw in an op amp to avoid that node altogether:
simulate this circuit
This way your programmer will "fight" against the op-amp, but if the resistance (R2) is high enough, the programmer would "win". During normal operations, the op-amp just buffers the voltage reference. If you go that way, pick an op-amp that accepts inputs and outputs close to the rails - Rail-to-rail I/O.